Railway Operation Simulator  v2.5.1
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <fstream>
38 #include <vector>
39 #include <vcl.h>
40 #include <stdio.h>
41 #include <algorithm> //for sort
42 
43 #pragma hdrstop
44 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
45 // They aren't all needed in each case but being together and identical they speed
46 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
47 // conjunction with 'use pre-compiled headers' in the project compiler options.
48 
49 #include "InterfaceUnit.h"
50 #include "GraphicUnit.h"
51 #include "DisplayUnit.h"
52 #include "TextUnit.h"
53 #include "TrainUnit.h"
54 #include "Utilities.h"
55 #include "TrackUnit.h"
56 #include "AboutUnit.h"
57 #include <fstream>
58 #include <dirent.h>
59 #include <Filectrl.hpp> //to check whether directories exist
60 
61 // ---------------------------------------------------------------------------
62 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
63 #pragma package(smart_init)
64 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
65 #pragma resource "*.dfm"
66 
68 
69 // Folder Names
70 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
71 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
72 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
73 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
74 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
75 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
76 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
77 
78 // ---------------------------------------------------------------------------
79 
80 __fastcall TInterface::TInterface(TComponent* Owner): TForm(Owner)
81 { // constructor
82  try
83  {
84  Screen->Cursor = TCursor(-11); // Hourglass;
85  DirOpenError = false;
86  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
87  // initial setup
88  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
89  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
91  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
92  // development stages (don't show on published versions)
93 
94  // check for presence of directories, creation failure probably indicates that the
95  // working folder is read-only
96  CurDir = GetCurrentDir();
97  if(!DirectoryExists(RAILWAY_DIR_NAME))
98  {
99  if(!CreateDir(RAILWAY_DIR_NAME))
100  {
101  DirOpenError = true;
102  }
103  }
104  if(!DirectoryExists(TIMETABLE_DIR_NAME))
105  {
106  if(!CreateDir(TIMETABLE_DIR_NAME))
107  {
108  DirOpenError = true;
109  }
110  }
111  if(!DirectoryExists(PERFLOG_DIR_NAME))
112  {
113  if(!CreateDir(PERFLOG_DIR_NAME))
114  {
115  DirOpenError = true;
116  }
117  }
118  if(!DirectoryExists(SESSION_DIR_NAME))
119  {
120  if(!CreateDir(SESSION_DIR_NAME))
121  {
122  DirOpenError = true;
123  }
124  }
125  if(!DirectoryExists(IMAGE_DIR_NAME))
126  {
127  if(!CreateDir(IMAGE_DIR_NAME))
128  {
129  DirOpenError = true;
130  }
131  }
132  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
133  {
134  if(!CreateDir(FORMATTEDTT_DIR_NAME))
135  {
136  DirOpenError = true;
137  }
138  }
139  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
140  {
141  if(!CreateDir(USERGRAPHICS_DIR_NAME))
142  {
143  DirOpenError = true;
144  }
145  }
146  if(DirOpenError)
147  {
148  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
150  "program operation may be restricted");
151  }
152 // ShowMessage("NOTE: APPDEACTIVATE etc Disabled in FormCreate");
153  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
154  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
155  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
156  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
157  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
158  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME;
159 
160  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
161 
162  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
163  PopupMenu->AutoHotkeys = maManual; // as above
164 
165  Utilities = new TUtilities;
166  RailGraphics = new TRailGraphics();
167 
168  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
169  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
170  MainScreen->Width = DispW * 16;
171  MainScreen->Height = DispH * 16;
172 
175  Utilities->ScreenElementWidth = DispW;
177  HiddenScreen = new TImage(Interface);
178  HiddenScreen->Width = MainScreen->Width;
179  HiddenScreen->Height = MainScreen->Height;
183  Track = new TTrack;
184  AllRoutes = new TAllRoutes;
189  SelectBitmap = new Graphics::TBitmap;
190  SelectBitmap->PixelFormat = pf8bit;
191  SelectBitmap->Transparent = true;
196  LengthWarningSentFlag = false;
197 
198  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
199  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
200  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
201  ResetAll(0);
202 
203  TempTTFileName = "";
204 
209 
210  RouteFlashDuration = 0.0;
211  PointsFlashDuration = 0.0;
212 
213  FloatingLabel->Color = clB4G5R5;
214  TrackElementPanel->Color = clB5G5R4;
215  InfoPanel->Color = clB4G5R5;
216 
217  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
218  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
219  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
220  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
221  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
222  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
223  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
224  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
225  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
226  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
227  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
228  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
229  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
230  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
231  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
232  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
233  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
234  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
235  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
236  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
237  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
238  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
239  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
240  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
241  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
242  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
243  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
244  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
245  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
246  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
247  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
248  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
249  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
250  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
251  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
252  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
253  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
254  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
255  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
256  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
257  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
258  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
259  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
260  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
261  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
262  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
263  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
264  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
265  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
266  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
267  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
268  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
269  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
270  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
271  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
272  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
273  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
274  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
275  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
276  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
277  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
278  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
279  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
280  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
281  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
282  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
283  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
284  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
285  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
286  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
287  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
288  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
289  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
290  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
291  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
292  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
293  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
294  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
295  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
296  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
297  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
298  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
299  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
300  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
301  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
302  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
303  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
304  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
305  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
306  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
307  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
308  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
309  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
310  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
311  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
312  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
313  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
314  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
315  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
316  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
317  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
318  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
319  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
320  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
321  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
322  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
323  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
324  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
325  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
326  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
327  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
328  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
329  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
330  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
331  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
332  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
333  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
334  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
335  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
336  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
337  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
338  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
339  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
340  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
341  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
342  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
343  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
344  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
345  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
346  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
347  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
348  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
349  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
350  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
351  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
352  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
353  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
354  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
355  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
356  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
357  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
358  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
359  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
360  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
361  // below not in RailGraphics
362  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
363 
364  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
365  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
366  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
367  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
368  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
369  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
370  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
371  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
372  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
373  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
374  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
375  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
376  HomeButton->Glyph->LoadFromResourceName(0, "Home");
377  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
378  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
379  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
380  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
381  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
382  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
383  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
384  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
385  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
386  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
387  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
388  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
389  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
390  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
391  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
392  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
393  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
394  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
395  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
396  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
397  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
398  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
399  SigPrefButton->Glyph->LoadFromResourceName(0, "PrefSig");
400  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
401  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
402  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
403  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
404 
405  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
406  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
407  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
408  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
409  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
410  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
411  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
412 
413  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
414  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
415 
416  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
417  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
418  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
419  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
420  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
421  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
422 
423  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
424  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
425  SigsOnLeftImage1->Transparent = true;
426  SigsOnLeftImage2->Transparent = true;
427  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
428  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
429  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
430  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
431  SigsOnRightImage1->Transparent = true;
432  SigsOnRightImage2->Transparent = true;
433  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
434  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
435 
436 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
437  RailwayIcon = new TPicture;
438  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
439  Icon = RailwayIcon->Icon;
440  Application->Icon = RailwayIcon->Icon;
441 */
442 
443  AnsiString NL = '\n';
444  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
445  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
446  "Start new shuttle service from a feeder";
447 
448  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
449 
450  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
451  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
452  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
453 
454  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
455  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " + NL + "R";
456 
457  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
458 
459  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
460  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
461  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
462  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
463  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
464 
465  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
466  "Arrival time, departure time (with no events between) + location";
467 
468  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
469  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
470 
471  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
472  "and semicolons may only be used to" + NL + "separate service components.";
473 
474  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
475 
476  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
477 
478  TTLabel1->Caption = TTLabelStr1;
479  TTLabel2->Caption = TTLabelStr2;
480  TTLabel3->Caption = TTLabelStr3;
481  TTLabel4->Caption = TTLabelStr4;
482  TTLabel5->Caption = TTLabelStr5;
483  TTLabel6->Caption = TTLabelStr6;
484  TTLabel7->Caption = TTLabelStr7;
485  TTLabel9->Caption = TTLabelStr9;
486  TTLabel11->Caption = TTLabelStr11;
487  TTLabel12->Caption = TTLabelStr12;
488  TTLabel13->Caption = TTLabelStr13;
489  TTLabel15->Caption = TTLabelStr15;
490 
491  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
492 
493  AnsiString ColourStr = "";
494  std::ifstream ColFile((CurDir + "\\Background.col").c_str());
495  if(ColFile.fail())
496  {
497  Utilities->clTransparent = clB0G0R0; // default black background;
498  }
499  else
500  {
501  if(!(Utilities->CheckAndReadFileString(ColFile, ColourStr)))
502  {
503  Utilities->clTransparent = clB0G0R0; // default black background;
504  }
505  else if((ColourStr != "white") && (ColourStr != "black") && (ColourStr != "blue"))
506  {
507  Utilities->clTransparent = clB0G0R0; // default black background;
508  }
509  else
510  {
511  if(ColourStr == "white")
512  {
513  Utilities->clTransparent = TColor(0xFFFFFF);
514  }
515  else if(ColourStr == "blue")
516  {
517  Utilities->clTransparent = TColor(0x330000);
518  }
519  else
520  {
521  Utilities->clTransparent = TColor(0);
522  }
523  ColFile.close(); // added at v2.3.0, should have been in earlier
524  }
525  }
526 
527  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
528  AnsiString RHSigStr = "";
529  std::ifstream SignalFile((CurDir + "\\Signal.hnd").c_str());
530  if(SignalFile.fail())
531  {
532  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
533  SigsOnLeftImage1->Visible = true;
534  SigsOnLeftImage2->Visible = true;
535  SigsOnRightImage1->Visible = false;
536  SigsOnRightImage2->Visible = false;
537  SignalFile.close(); // close ifstream & open ofstream
538  std::ofstream SignalFile((CurDir + "\\Signal.hnd").c_str());
539  if(!SignalFile.fail()) // if it does fail then it will revert to LHS anyway on next load unless select RH sigs
540  {
541  Utilities->SaveFileString(SignalFile, "LHSignals");
542  }
543  SignalFile.close();
544  }
545  else
546  {
547  if(Utilities->CheckAndReadFileString(SignalFile, RHSigStr)) // if it fails then do nothing
548  {
549  if(RHSigStr == "RHSignals")
550  {
551  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program
552  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
554  {
556  }
557  else
558  {
560  }
561  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
562  SigsOnLeftImage1->Visible = false;
563  SigsOnLeftImage2->Visible = false;
564  SigsOnRightImage1->Visible = true;
565  SigsOnRightImage2->Visible = true;
566  SignalFile.close();
567  }
568  else
569  {
570  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
571  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
572  SigsOnLeftImage1->Visible = true;
573  SigsOnLeftImage2->Visible = true;
574  SigsOnRightImage1->Visible = false;
575  SigsOnRightImage2->Visible = false;
576  SignalFile.close(); // close ifstream & open ofstream
577  std::ofstream SignalFile((CurDir + "\\Signal.hnd").c_str());
578  if(!SignalFile.fail()) // if it does fail then it will revert to LHS anyway on next load unless select RH sigs
579  {
580  Utilities->SaveFileString(SignalFile, "LHSignals");
581  }
582  SignalFile.close();
583  }
584  }
585  }
586 
587  SelectBitmap->TransparentColor = Utilities->clTransparent;
588  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
590  TextBox->Color = clB3G3R3;
592 
593  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
594  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
595 
596  std::ifstream SplashFile((CurDir + "\\GNU").c_str());
597  if(SplashFile.fail())
598  {
599  ShowMessage(
600  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>.");
601  std::ofstream SplashFile((CurDir + "\\GNU").c_str());
602  if(!SplashFile.fail())
603  SplashFile.close();
604  }
605 
606  if((Screen->Width < 1024) || (Screen->Height < 768))
607  {
608  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
609  }
610 
611  SkipFormResizeEvent = true; // added at v2.1.0
612  MasterClock->Enabled = true;
613  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
614  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
615  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
616  // has to come after Visible = true or doesn't show
617  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
618  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
619  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
620  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
621  AllSetUpFlag = true;
622  MissedTicks = 0;
623  TotalTicks = 0;
625  SetLevel1Mode(131); // to reset background colour mode menu choices
626  Screen->Cursor = TCursor(-2); // Arrow
627  SkipFormResizeEvent = false; // added at v2.1.0
628  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
629 
630  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
631  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
632  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
633  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
634  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
635  HighlightPanel->Color = TColor(0x33CCFF);
637  MTBFEditBox->Visible = false; // new at v2.4.0
638  MTBFLabel->Visible = false;
641  TTStartTimePtr = 0;
642  TTFirstServicePtr = 0;
643  TTLastServicePtr = 0;
644  Track->OverrideAndHideSignalBridgeMessage = false; //added at v2.5.1 to allow facing signals before bridges - with a warning
645  ConflictPanel->Visible = false;
646  TTClockAdjustWarningPanel->Visible = false;
647  TTClockAdjustWarningHide = false;
648  LastNonCtrlOrShiftKeyDown = -1; //set to no key
649 
650  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
651 
652  // below added at v2.4.0 so able to load session files with the correct decimal point
653  Utilities->DecimalPoint = '.'; // default case is full stop
654  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
656  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
657  {
658  Utilities->SetLocaleResultOK = false;
659  }
660  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
661  struct lconv *conv = &Locale;
662  // read the locality conversion structure
663  conv = localeconv(); // this is what updates the structure
664  Utilities->DecimalPoint = conv->decimal_point[0];
665  }
666 
667  catch(const EFOpenError &e)
668  {
669  TMsgDlgButtons But;
670  But << mbOK;
671  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
672  Application->Terminate();
673  }
674 
675  catch(const Exception &e)
676  {
677  TMsgDlgButtons But;
678  But << mbOK;
679  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
680  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
681  ErrorLog(115, e.Message);
682  Application->Terminate();
683  }
684 }
685 
686 // ---------------------------------------------------------------------------
687 
689 { // destructor
690  try
691  {
692  SkipFormResizeEvent = true; // added at v2.1.0
693  delete NonSigRouteStartMarker;
694  delete SigRouteStartMarker;
695  delete AutoRouteStartMarker;
696  delete PointFlash;
697  delete SelectBitmap;
698  delete TrainController;
699  delete EveryPrefDir;
700  delete ConstructRoute;
701  delete ConstructPrefDir;
702  delete AllRoutes;
703  delete Track;
704  delete TextHandler;
705  delete HiddenDisplay;
706  delete HiddenScreen;
707  delete Display;
708  delete RailGraphics;
709  delete Utilities;
710  DeleteFile(TempTTFileName); //added after v2.4.3 to prevent temporary files building up
711  }
712  catch(const Exception &e)
713  {
714  ErrorLog(116, e.Message);
715  }
716 }
718 
719 // ---------------------------------------------------------------------------
720 
721 void __fastcall TInterface::FormCreate(TObject *Sender)
722 { // these functions have to be defined here to take effect when application activated & deactivated
723  try
724  {
725  Application->OnDeactivate = AppDeactivate;
726  Application->OnActivate = AppActivate;
727  }
728  catch(const Exception &e)
729  {
730  ErrorLog(117, e.Message);
731  }
732 }
733 
734 // ---------------------------------------------------------------------------
735 
736 void __fastcall TInterface::AppDeactivate(TObject *Sender)
737 { // pause operation if operating & stop the master clock
738  try
739  {
741  {
742  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
743  { // by Matt Blades 30/06/11
747  Screen->Cursor = TCursor(-2); // Arrow
748  Track->RouteFlashFlag = false;
749  ClearandRebuildRailway(48); // to get rid of displayed route
750  }
751  if(Track->PointFlashFlag)
752  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
753  {
755  Track->PointFlashFlag = false;
757  Screen->Cursor = TCursor(-2); // Arrow
758  }
761  }
762  MasterClock->Enabled = false;
763  }
764  catch(const Exception &e)
765  {
766  ErrorLog(118, e.Message);
767  }
768 }
769 
770 // ---------------------------------------------------------------------------
771 
772 void __fastcall TInterface::AppActivate(TObject *Sender)
773 { // restart the master clock providing Interface constructor has run
774  try
775  {
776  if(AllSetUpFlag)
777  {
778  MasterClock->Enabled = true;
779  }
780  }
781  catch(const Exception &e)
782  {
783  ErrorLog(119, e.Message);
784  }
785 }
786 
787 // ---------------------------------------------------------------------------
788 
789 UnicodeString TInterface::GetVersion()
790 {
791  DWORD VersionHandle;
792  DWORD VersionSize;
793  LPBYTE pBuffer;
794  UnicodeString strVersion = L"N/A";
795 
796  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
797  if(VersionSize)
798  {
799  pBuffer = new BYTE[VersionSize];
800 
801  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
802  {
803  VS_FIXEDFILEINFO *fi;
804  UINT buflen;
805 
806  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
807  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
808  {
809  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
810  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS)
811  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
812  );
813  }
814  }
815 
816  delete[]pBuffer;
817  }
818 
819  return L" v" + strVersion;
820 }
821 
822 // ---------------------------------------------------------------------------
823 // Track Build Interface
824 // ---------------------------------------------------------------------------
825 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
826 {
827  try
828  {
829  TrainController->LogEvent("BuildTrackMenuItemClick");
830  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
832  SetLevel1Mode(0);
833  Utilities->CallLogPop(1159);
834  }
835  catch(const Exception &e)
836  {
837  ErrorLog(120, e.Message);
838  }
839 }
840 // ---------------------------------------------------------------------------
841 
842 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
843 {
844  try
845  {
846  TrainController->LogEvent("AddTrackButtonClick");
847  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
849  SetLevel1Mode(38);
852  Utilities->CallLogPop(1162);
853  }
854  catch(const Exception &e)
855  {
856  ErrorLog(121, e.Message);
857  }
858 }
859 
860 // ---------------------------------------------------------------------------
861 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
862 {
863  try
864  {
865  TrainController->LogEvent("SpeedButtonClick");
866  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
867  if(((TSpeedButton*)Sender)->Down)
868  {
869  CurrentSpeedButton = (TSpeedButton*)Sender;
870 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
871  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
872  }
873  else
874  CurrentSpeedButton = 0;
875  SelectionValid = false;
876  ReselectMenuItem->Enabled = false;
877  Utilities->CallLogPop(1163);
878  }
879  catch(const Exception &e)
880  {
881  ErrorLog(122, e.Message);
882  }
883 }
884 
885 // ---------------------------------------------------------------------------
886 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
887 {
888  try
889  {
890  TrainController->LogEvent("TrackOKButtonClick");
891  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
892  SelectionValid = false;
894  bool LocError;
895  int HLoc, VLoc;
896  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
897 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
898  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
899  // if successful repositions TrackVector & builds TrackMap
900  {
901  if(LocError) // links not complete or other error - show offending element
902  {
903  while((Display->DisplayOffsetH - HLoc) > 0)
904  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
905  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
907  while((Display->DisplayOffsetV - VLoc) > 0)
908  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
909  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
912  Display->InvertElement(0, HLoc * 16, VLoc * 16);
913  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
914  ClearandRebuildRailway(1); // to clear inversion
916  SetLevel1Mode(39);
917  Level2TrackMode = AddTrack; // go to add track regardless of where started from
919  Utilities->CallLogPop(0);
920  return;
921  }
922  else
923  { // reach here if there are no track elements
924  ShowMessage("Unable to set any track links");
926  SetLevel1Mode(40);
928  SetLevel2TrackMode(4); // go to add track regardless of where started from
929  Utilities->CallLogPop(1);
930  return;
931  }
932  }
933  else
934  {
935  // success ('TrackFinished' set in TryToConnectTrack)
936  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
937  ShowMessage("Successful Completion");
938  }
939 // success if reach here ('TrackFinished' set in TryToConnectTrack)
941  {
943  SetLevel1Mode(41);
945  }
946  else
947  {
949  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
950  }
951  Utilities->CallLogPop(2);
952  }
953  catch(const Exception &e)
954  {
955  ErrorLog(3, e.Message);
956  }
957 }
958 
959 // ---------------------------------------------------------------------------
960 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
961 {
962  try
963  {
964  TrainController->LogEvent("SetGapsButtonClick");
965  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
966  SelectionValid = false;
967  ReselectMenuItem->Enabled = false;
969  SetLevel1Mode(42);
972  Utilities->CallLogPop(1164);
973  }
974  catch(const Exception &e)
975  {
976  ErrorLog(123, e.Message);
977  }
978 }
979 
980 // ---------------------------------------------------------------------------
981 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
982 {
983  try
984  {
985  TrainController->LogEvent("AddTextButtonClick");
986  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
988  SetLevel1Mode(43);
991  Utilities->CallLogPop(1165);
992  }
993  catch(const Exception &e)
994  {
995  ErrorLog(124, e.Message);
996  }
997 }
998 
999 // ---------------------------------------------------------------------------
1000 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
1001 {
1002  try
1003  {
1004  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1005  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1007  SetLevel1Mode(44);
1009  SetLevel2TrackMode(8);
1010  Utilities->CallLogPop(1166);
1011  }
1012  catch(const Exception &e)
1013  {
1014  ErrorLog(125, e.Message);
1015  }
1016 }
1017 
1018 // ---------------------------------------------------------------------------
1019 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1020 {
1021  try
1022  {
1023  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1024  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1025  if(Key == '\x0D') // CR
1026  {
1027  if(TextBox->Text != "") // if blank then don't save
1028  {
1029  if(Display->GetFont()->Color == clB5G5R5) // white
1030  {
1031  TFont *TempFont = new TFont;
1032  TempFont->Assign(Display->GetFont());
1033  TempFont->Color = clB0G0R0; // change to black for vector & saving
1034  Display->SetFont(TempFont);
1035  delete TempFont;
1036  }
1037  TFont *DisplayFont = Display->GetFont();
1038  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1039  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1041  }
1042  EditMenu->Enabled = true;
1043  TextBox->Visible = false;
1044  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1045  }
1046  else if(Key == '\x1B') // escape
1047  {
1048  TextBox->Visible = false;
1049  }
1050  Utilities->CallLogPop(3);
1051  }
1052  catch(const Exception &e)
1053  {
1054  ErrorLog(4, e.Message);
1055  }
1056 }
1057 
1058 // ---------------------------------------------------------------------------
1059 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1060 {
1061  try
1062  {
1063  TrainController->LogEvent("LocationNameButtonClick");
1064  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1066  SetLevel1Mode(45);
1068  SetLevel2TrackMode(9);
1069  Utilities->CallLogPop(1167);
1070  }
1071  catch(const Exception &e)
1072  {
1073  ErrorLog(126, e.Message);
1074  }
1075 }
1076 
1077 // ---------------------------------------------------------------------------
1078 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1079 {
1080  try
1081  {
1082  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1083  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1084  if(Track->LNPendingList.empty())
1085  {
1086  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1088  SetLevel1Mode(46);
1090  SetLevel2TrackMode(10);
1091  Utilities->CallLogPop(4);
1092  return;
1093  }
1094  if(Key == '\x1B') // escape
1095  {
1096  Track->LNPendingList.clear(); // get rid of existing entry
1098  SetLevel1Mode(47);
1100  SetLevel2TrackMode(11);
1101  Utilities->CallLogPop(5);
1102  return;
1103  }
1104  if(Key == '\x0D')
1105  {
1106  Screen->Cursor = TCursor(-11); // Hourglass;
1108  AnsiString ExistingName;
1109  if(Track->LNPendingList.front() > -1)
1110  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1111  else
1112  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1113  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1114  { // name allocated to a different location
1115  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1116  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1117  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1118  if(button == IDNO)
1119  {
1120  Track->LNPendingList.clear(); // get rid of existing entry
1121  Screen->Cursor = TCursor(-2); // Arrow
1123  SetLevel1Mode(48);
1125  SetLevel2TrackMode(12);
1126  Utilities->CallLogPop(6);
1127  return;
1128  }
1130  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1131  int HPos, VPos;
1132  bool UseExistingPosition = false;
1133  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1134  {;
1135  } // condition not used
1136  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1137  // but, the location to be named may also have an existing name, in which case that needs to be erased
1138  // and the position re-used
1139  if(ExistingName != "")
1140  {
1141  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1142  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1143  }
1144  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1145  Screen->Cursor = TCursor(-2); // Arrow
1147  SetLevel1Mode(49);
1149  SetLevel2TrackMode(13);
1150  Utilities->CallLogPop(7);
1151  return;
1152  }
1153  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1154  { // same name being entered again
1155  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1156  // but in case the name is not already in text vector erase it and re-add it
1157  // if it wasn't in the vector erasing it has no effect
1158  int HPos, VPos;
1159  bool UseExistingPosition = false;
1160  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1161  UseExistingPosition = true;
1162  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1163  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1164  Screen->Cursor = TCursor(-2); // Arrow
1166  SetLevel1Mode(50);
1168  SetLevel2TrackMode(14);
1169  Utilities->CallLogPop(8);
1170  return;
1171  }
1172  else
1173  { // either a new name for an unnamed location, or a different name for a named location
1174  // check validity of entry
1175  AnsiString LocStr = LocationNameTextBox->Text;
1176  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1177  LocationNameTextBox->Text = LocStr; // reset this as used below
1178 /* drop this, now covered by ...Trim() above
1179  //strip leading spaces
1180  while((LocStr != "") && (LocStr[1] == ' '))
1181  {
1182  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1183  }
1184 */
1185  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1186  {
1187  Screen->Cursor = TCursor(-2); // Arrow
1188  ShowMessage("Location name can't begin with a number");
1190  SetLevel1Mode(51);
1192  SetLevel2TrackMode(15);
1193  Utilities->CallLogPop(776);
1194  return;
1195  }
1196  if(LocStr.Length() > 50)
1197  {
1198  Screen->Cursor = TCursor(-2); // Arrow
1199  ShowMessage("Location name too long, 50 characters maximum");
1201  SetLevel1Mode(122);
1203  SetLevel2TrackMode(55);
1204  Utilities->CallLogPop(1735);
1205  return;
1206  }
1207  for(int x = 1; x <= LocStr.Length(); x++)
1208  {
1209  char Ch = LocStr[x];
1210  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1211  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1212  {
1213  Screen->Cursor = TCursor(-2); // Arrow
1214  ShowMessage(
1215  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1217  SetLevel1Mode(52);
1219  SetLevel2TrackMode(16);
1220  Utilities->CallLogPop(777);
1221  return;
1222  }
1223  }
1224  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1225  {
1226  Screen->Cursor = TCursor(-2); // Arrow
1227  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1229  SetLevel1Mode(53);
1231  SetLevel2TrackMode(17);
1232  Utilities->CallLogPop(778);
1233  return;
1234  }
1235  Track->EnterLocationName(2, LocStr, false);
1236  // need to check if the location already has a name, and if so erase it from the textvector
1237  int HPos, VPos;
1238  bool UseExistingPosition = false;
1239  if(ExistingName != "")
1240  {
1241  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1242  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1243  }
1244  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1245  Screen->Cursor = TCursor(-2); // Arrow
1247  SetLevel1Mode(54);
1249  SetLevel2TrackMode(18);
1250  Utilities->CallLogPop(9);
1251  return;
1252  }
1253  }
1254  Screen->Cursor = TCursor(-2); // Arrow
1255  Utilities->CallLogPop(10);
1256  }
1257  catch(const Exception &e)
1258  {
1259  ErrorLog(5, e.Message);
1260  }
1261 }
1262 
1263 // ---------------------------------------------------------------------------
1264 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1265 {
1266  try
1267  {
1268  TrainController->LogEvent("SetLengthsButtonClick");
1269  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1270  SelectLengthsFlag = false;
1271  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1273  SetLevel1Mode(55);
1275  SetLevel2TrackMode(19);
1276  Utilities->CallLogPop(1168);
1277  }
1278  catch(const Exception &e)
1279  {
1280  ErrorLog(127, e.Message);
1281  }
1282 }
1283 
1284 // ---------------------------------------------------------------------------
1285 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1286 {
1287  try
1288  {
1289  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1290  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1291  int Dist = 0, SpeedLimit = 0;
1292  AnsiString DistanceStr = DistanceBox->Text;
1293  if(SelectLengthsFlag && (DistanceStr == ""))
1294  DistanceStr = "No change";
1295  AnsiString SpeedStr = SpeedLimitBox->Text;
1296  if(SelectLengthsFlag && (SpeedStr == ""))
1297  SpeedStr = "No change";
1298  if(SelectLengthsFlag)
1299  {
1300  if(DistanceStr == "No change")
1301  Dist = -1; // i.e.don't change
1302  if(SpeedStr == "No change")
1303  SpeedLimit = -1; // i.e.don't change
1304  }
1305  else
1306  {
1307  if(DistanceStr == AnsiString(OverallDistance))
1308  Dist = -1; // i.e.don't change
1309  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1310  SpeedLimit = -1; // i.e.don't change
1311  }
1312  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1313  {
1314  ShowMessage("One or more entries too long");
1315  Utilities->CallLogPop(11);
1316  return;
1317  }
1318  if((DistanceStr == "") || (SpeedStr == ""))
1319  {
1320  ShowMessage("One or more entries blank");
1321  Utilities->CallLogPop(12);
1322  return;
1323  }
1324  if(SelectLengthsFlag && (Dist != -1))
1325  {
1326  for(int x = 1; x <= DistanceStr.Length(); x++)
1327  {
1328  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1329  {
1330  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1331  Utilities->CallLogPop(1415);
1332  return;
1333  }
1334  }
1335  }
1336  if(!SelectLengthsFlag)
1337  {
1338  for(int x = 1; x <= DistanceStr.Length(); x++)
1339  {
1340  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1341  {
1342  ShowMessage("Distance must be a positive whole number");
1343  Utilities->CallLogPop(13);
1344  return;
1345  }
1346  }
1347  }
1348  if(SelectLengthsFlag && (SpeedLimit != -1))
1349  {
1350  for(int x = 1; x <= SpeedStr.Length(); x++)
1351  {
1352  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1353  {
1354  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1355  Utilities->CallLogPop(1416);
1356  return;
1357  }
1358  }
1359  }
1360  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1361  {
1362  for(int x = 1; x <= SpeedStr.Length(); x++)
1363  {
1364  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1365  {
1366  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1367  Utilities->CallLogPop(14);
1368  return;
1369  }
1370  }
1371  }
1372  if(Dist != -1)
1373  Dist = DistanceStr.ToInt();
1374  if(SpeedLimit != -1)
1375  SpeedLimit = SpeedStr.ToInt();
1376 /* don't need this with new condition below
1377  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1378  {
1379  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1380  Dist = 20;
1381  }
1382 */
1383  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1384  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1385  {
1386  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1387  Utilities->CallLogPop(15);
1388  return;
1389  }
1390  DistanceBox->Text = "";
1391  SpeedLimitBox->Text = "";
1392  if(SelectLengthsFlag)
1393  {
1394  int LowSelectHLoc = SelectBitmapHLoc;
1395  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1396  int LowSelectVLoc = SelectBitmapVLoc;
1397  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1398  bool FoundFlag;
1399  bool NamedLocPresent = false;
1400  if((Dist != -1) && (Dist != DefaultTrackLength))
1401  {
1402  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1403  {
1404  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1405  {
1407  NamedLocPresent = true;
1408  }
1409  }
1410  }
1411  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1412  {
1413  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
1414  }
1415 
1416  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1417  {
1418  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
1419  }
1420 
1421  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1422  {
1423  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1424  {
1425  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1426  if(FoundFlag)
1427  {
1428  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1429  {
1430  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1431  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1432  {
1433  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1434  }
1435  }
1436  if(SpeedLimit > -1)
1437  {
1438  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1439  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1440  {
1441  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1442  }
1443  }
1444  }
1445  }
1446  }
1447  TrackLengthPanel->Visible = false;
1448  SelectLengthsFlag = false; // go back to normal distance setting mode
1449  }
1450  else
1451  {
1452  SetTrackLengths(1, Dist, SpeedLimit);
1453  }
1455  SetLevel1Mode(57);
1457  SetLevel2TrackMode(21);
1458  Utilities->CallLogPop(16);
1459  }
1460  catch(const Exception &e)
1461  {
1462  ErrorLog(6, e.Message);
1463  }
1464 }
1465 
1466 // ---------------------------------------------------------------------------
1467 void __fastcall TInterface::LengthCancelButtonClick(TObject *Sender)
1468 {
1469  try
1470  {
1471  TrainController->LogEvent("LengthCancelButtonClick");
1472  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1473  DistanceBox->Text = "";
1474  SpeedLimitBox->Text = "";
1475  TrackLengthPanel->Visible = false;
1476  SelectLengthsFlag = false; // go back to normal distance setting mode
1478  SetLevel1Mode(59);
1480  SetLevel2TrackMode(23);
1481  Utilities->CallLogPop(1169);
1482  }
1483  catch(const Exception &e)
1484  {
1485  ErrorLog(128, e.Message);
1486  }
1487 }
1488 
1489 // ---------------------------------------------------------------------------
1490 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1491 {
1492  try
1493  {
1494  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1495  TMsgDlgButtons Buttons;
1496  Buttons << mbYes << mbNo;
1497  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1498  {
1499  // leave all as was before
1500  Utilities->CallLogPop(17);
1501  return;
1502  }
1503  else
1504  {
1505  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1506  DistanceBox->Text = "";
1507  SpeedLimitBox->Text = "";
1508  if(SelectLengthsFlag)
1509  {
1510  int LowSelectHLoc = SelectBitmapHLoc;
1511  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1512  int LowSelectVLoc = SelectBitmapVLoc;
1513  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1514  bool FoundFlag;
1515  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1516  {
1517  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1518  {
1519  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1520  if(FoundFlag)
1521  {
1523  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1524  {
1526  }
1528  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1529  {
1531  }
1532  }
1533  }
1534  }
1535  TrackLengthPanel->Visible = false;
1536 // ClearandRebuildRailway(47); don't need this
1537  SelectLengthsFlag = false; // go back to normal distance setting mode
1538  }
1539  else
1540  {
1541  TrackLengthPanel->Visible = false;
1542  bool FoundFlag;
1543  if(ConstructPrefDir->PrefDirSize() == 0)
1544  {
1545  Utilities->CallLogPop(1120);
1546  return;
1547  }
1548  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1549  {
1550  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1551  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1552  FoundFlag));
1553  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1554  // only set the relevant track to default length & speed limit
1555  {
1556  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1557  {
1558  TrackElement.Length01 = DefaultTrackLength;
1559  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1560  }
1561  else
1562  {
1563  TrackElement.Length23 = DefaultTrackLength;
1564  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1565  }
1566  }
1567  else // any other 1 track element, including platforms being present
1568  {
1569  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1570  {
1571  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1572  AnsiString(TrackElement.VLoc));
1573  }
1574  TrackElement.Length01 = DefaultTrackLength;
1575  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1576  TrackElement.Length23 = -1;
1577  TrackElement.SpeedLimit23 = -1;
1578  }
1579  }
1580  }
1582  SetLevel1Mode(61);
1584  SetLevel2TrackMode(25);
1585  }
1586  Utilities->CallLogPop(18);
1587  }
1588  catch(const Exception &e)
1589  {
1590  ErrorLog(7, e.Message);
1591  }
1592 }
1593 
1594 // ---------------------------------------------------------------------------
1595 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1596 {
1597  try
1598  {
1599  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1600  TMsgDlgButtons Buttons;
1601  Buttons << mbYes << mbNo;
1602  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1603  {
1604  // leave all as was before
1605  Utilities->CallLogPop(19);
1606  return;
1607  }
1608  else
1609  {
1611  }
1612  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1613  DistanceBox->Text = "";
1614  SpeedLimitBox->Text = "";
1615  TrackLengthPanel->Visible = false;
1616  SelectLengthsFlag = false; // go back to normal distance setting mode
1618  SetLevel1Mode(63);
1620  SetLevel2TrackMode(27);
1621  Utilities->CallLogPop(20);
1622  }
1623  catch(const Exception &e)
1624  {
1625  ErrorLog(8, e.Message);
1626  }
1627 }
1628 
1629 // ---------------------------------------------------------------------------
1630 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1631 {
1632  try
1633  {
1634  TrainController->LogEvent("ExitTrackButtonClick");
1635  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1636  if(Level2TrackMode == CutMoving)
1637  {
1638  Level2TrackMode = Pasting; // to paste the selection
1639  SetLevel2TrackMode(53);
1640  }
1641  DevelopmentPanel->Visible = false; // development use only
1642  ScreenGridFlag = false;
1643  SelectionValid = false;
1644  Track->SelectGraphicVector.clear();
1645  // delete all unwanted TPictures in UserGraphicMap
1646  if(!Track->UserGraphicMap.empty()) // if empty skip it
1647  {
1648  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1649  do
1650  {
1651  bool GraphicFoundInVector = false;
1652  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1653  {
1654  if(UGMIt->first == UGVIt->FileName)
1655  {
1656  GraphicFoundInVector = true;
1657  break;
1658  }
1659  }
1660  if(!GraphicFoundInVector)
1661  {
1662  delete UGMIt->second;
1663  Track->UserGraphicMap.erase(UGMIt);
1664  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1665  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1666  }
1667  else
1668  {
1669  UGMIt++;
1670  }
1671  }
1672  while(UGMIt != Track->UserGraphicMap.end());
1673  }
1674  Level1Mode = BaseMode;
1675  SetLevel1Mode(2);
1676  Utilities->CallLogPop(1170);
1677  }
1678  catch(const Exception &e)
1679  {
1680  ErrorLog(129, e.Message);
1681  }
1682 }
1683 
1684 // ---------------------------------------------------------------------------
1685 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1686 {
1687  try
1688  {
1689  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1690  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1691  if(TextOrUserGraphicGridVal == 1)
1692  {
1694  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1695  }
1696  else if(TextOrUserGraphicGridVal == 2)
1697  {
1699  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1700  }
1701  else if(TextOrUserGraphicGridVal == 4)
1702  {
1704  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1705  }
1706  else if(TextOrUserGraphicGridVal == 8)
1707  {
1709  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1710  }
1711  else
1712  {
1714  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1715  }
1716  Utilities->CallLogPop(1171);
1717  }
1718  catch(const Exception &e)
1719  {
1720  ErrorLog(130, e.Message);
1721  }
1722 }
1723 
1724 // ---------------------------------------------------------------------------
1725 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1726 {
1727  try
1728  {
1729  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1730  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1732  {
1734  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1735  }
1737  {
1739  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1740  }
1742  {
1744  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1745 // set all signal glyphs to ground signals
1747  }
1748  else
1749  {
1751  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1752 // set all signal glyphs to normal signals
1754  }
1755  Utilities->CallLogPop(1869);
1756  }
1757  catch(const Exception &e)
1758  {
1759  ErrorLog(180, e.Message);
1760  }
1761 }
1762 
1763 // ---------------------------------------------------------------------------
1764 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1765 {
1766  try
1767  {
1768  TrainController->LogEvent("FontButtonClick");
1769  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1770  FontDialog->Font = Display->GetFont(); //sets the dialog box font to the currently used font
1771  FontDialog->Execute(); //this displays the dialog box
1772  if(FontDialog->Font->Color == clB5G5R5) //white
1773  FontDialog->Font->Color = clB0G0R0; //black - don't store white in font, will display black as white on dark backgrounds
1774  Display->SetFont(FontDialog->Font); //sets the displayed font to the output from the dialog box
1775  if(TextBox->Visible)
1776  TextBox->SetFocus();
1777  else if(LocationNameTextBox->Visible)
1778  LocationNameTextBox->SetFocus();
1779  Utilities->CallLogPop(1172);
1780  }
1781  catch(const Exception &e)
1782  {
1783  ErrorLog(131, e.Message);
1784  }
1785 }
1786 
1787 // ---------------------------------------------------------------------------
1788 
1789 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1790 {
1791  try
1792  {
1793  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1794  if(ScreenGridFlag)
1795  {
1796  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1797  ScreenGridFlag = false;
1798  }
1799  else
1800  {
1801  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1802  ScreenGridFlag = true;
1803  }
1805  Utilities->CallLogPop(89);
1806  }
1807  catch(const Exception &e)
1808  {
1809  ErrorLog(33, e.Message);
1810  }
1811 }
1812 
1813 // ---------------------------------------------------------------------------
1814 // PrefDir Interface
1815 // ---------------------------------------------------------------------------
1816 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
1817 {
1818  try
1819  {
1820  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
1821  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
1823  SetLevel1Mode(3);
1824  Utilities->CallLogPop(1173);
1825  }
1826  catch(const Exception &e)
1827  {
1828  ErrorLog(132, e.Message);
1829  }
1830 }
1831 
1832 // ---------------------------------------------------------------------------
1833 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
1834 {
1835  try
1836  {
1837  TrainController->LogEvent("AddPrefDirButtonClick");
1838  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
1839  if(ConstructPrefDir->PrefDirSize() == 0)
1840  {
1841  ShowMessage("No preferred direction selection");
1842  Utilities->CallLogPop(22);
1843  return;
1844  }
1845  Screen->Cursor = TCursor(-11); // Hourglass;
1849  SetLevel1Mode(4);
1850  Screen->Cursor = TCursor(-2); // Arrow
1851  Utilities->CallLogPop(23);
1852  }
1853  catch(const Exception &e)
1854  {
1855  ErrorLog(10, e.Message);
1856  }
1857 }
1858 
1859 // ---------------------------------------------------------------------------
1860 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
1861 {
1862  try
1863  {
1864  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
1865  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
1866  TMsgDlgButtons Buttons;
1867  Buttons << mbYes << mbNo;
1868  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
1869  {
1870  Utilities->CallLogPop(24);
1871  return;
1872  }
1873  // leave all as was before pressed DeleteAllPrefDirButton
1874  else
1875  {
1880  SetLevel1Mode(5);
1881  }
1882  Utilities->CallLogPop(25);
1883  }
1884  catch(const Exception &e)
1885  {
1886  ErrorLog(11, e.Message);
1887  }
1888 }
1889 // ---------------------------------------------------------------------------
1890 
1891 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
1892 {
1893  try
1894  {
1895  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
1896  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
1897  ResetChangedFileDataAndCaption(18, false);
1898 // RlyFile = false; - don't alter this just for PrefDir changes
1899  Screen->Cursor = TCursor(-11); // Hourglass;
1900  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1901  {
1904  }
1907  SetLevel1Mode(81); // all PrefDir truncated
1908  Screen->Cursor = TCursor(-2); // Arrow
1909  Utilities->CallLogPop(1591);
1910  }
1911  catch(const Exception &e)
1912  {
1913  ErrorLog(46, e.Message);
1914  }
1915 }
1916 
1917 // ---------------------------------------------------------------------------
1918 
1919 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
1920 {
1921  try
1922  {
1923  TrainController->LogEvent("ExitPrefDirButtonClick");
1924  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
1925  Level1Mode = BaseMode;
1926  SetLevel1Mode(6);
1927  Utilities->CallLogPop(1554);
1928  }
1929  catch(const Exception &e)
1930  {
1931  ErrorLog(133, e.Message);
1932  }
1933 }
1934 
1935 // ---------------------------------------------------------------------------
1936 // Operate Railway Interface
1937 // ---------------------------------------------------------------------------
1938 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
1939 {
1940  try
1941  {
1942  TrainController->LogEvent("OperateRailwayMenuItemClick");
1943  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
1944  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
1945  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
1946  Level1Mode = OperMode;
1947  SetLevel1Mode(7);
1948  Utilities->CallLogPop(26);
1949  }
1950  catch(const Exception &e)
1951  {
1952  ErrorLog(12, e.Message);
1953  }
1954 }
1955 
1956 // ---------------------------------------------------------------------------
1957 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
1958 {
1959  try
1960  {
1961  TrainController->LogEvent("StartOperationButtonClick");
1962  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
1964  {
1966  SetLevel2OperMode(0);
1967  }
1968  else
1969  {
1971  SetLevel2OperMode(1);
1972  }
1973  Utilities->CallLogPop(1175);
1974  }
1975  catch(const Exception &e)
1976  {
1977  ErrorLog(37, e.Message);
1978  }
1979 }
1980 
1981 // ---------------------------------------------------------------------------
1982 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
1983  // must have PrefDirs to be available
1984 {
1985  try
1986  {
1987  TrainController->LogEvent("AutoSigsButtonClick");
1988  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
1989  AutoSigsFlag = true;
1990  PreferredRoute = true;
1991  ConsecSignalsRoute = true;
1992 
1993  AutoSigsButton->Enabled = false;
1994  SigPrefButton->Enabled = true;
1995  UnrestrictedButton->Enabled = true;
1996 
1997  InfoPanel->Visible = true;
1998  if(Level2OperMode == PreStart)
1999  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2000  else
2001  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2002  InfoCaptionStore = InfoPanel->Caption;
2003  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2004  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2005  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2007  Utilities->CallLogPop(28);
2008  }
2009  catch(const Exception &e)
2010  {
2011  ErrorLog(14, e.Message);
2012  }
2013 }
2014 
2015 // ---------------------------------------------------------------------------
2016 void __fastcall TInterface::SigPrefButtonClick(TObject *Sender)
2017  // must have PrefDirs to be available
2018 {
2019  try
2020  {
2021  TrainController->LogEvent("SigPrefButtonClick");
2022  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2023  AutoSigsFlag = false;
2024  PreferredRoute = true;
2025  ConsecSignalsRoute = true;
2026 
2027  AutoSigsButton->Enabled = true;
2028  SigPrefButton->Enabled = false;
2029  UnrestrictedButton->Enabled = true;
2030 
2031  InfoPanel->Visible = true;
2032  if(Level2OperMode == PreStart)
2033  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2034  else
2035  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2036  InfoCaptionStore = InfoPanel->Caption;
2037  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2038  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2039  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2041  Utilities->CallLogPop(29);
2042  }
2043  catch(const Exception &e)
2044  {
2045  ErrorLog(15, e.Message);
2046  }
2047 }
2048 
2049 // ---------------------------------------------------------------------------
2050 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2051 {
2052  try
2053  {
2054  TrainController->LogEvent("NoSigNonPrefButtonClick");
2055  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2056  AutoSigsFlag = false;
2057  PreferredRoute = false;
2058  ConsecSignalsRoute = false;
2059  if(EveryPrefDir->PrefDirSize() > 0)
2060  {
2061  AutoSigsButton->Enabled = true;
2062  SigPrefButton->Enabled = true;
2063  UnrestrictedButton->Enabled = false;
2064  }
2065  else
2066  {
2067  AutoSigsButton->Enabled = false;
2068  SigPrefButton->Enabled = false;
2069  UnrestrictedButton->Enabled = false;
2070  }
2071  InfoPanel->Visible = true;
2072  if(Level2OperMode == PreStart)
2073  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2074  else
2075  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2076  InfoCaptionStore = InfoPanel->Caption;
2077  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2078  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2079  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2081  Utilities->CallLogPop(30);
2082  }
2083  catch(const Exception &e)
2084  {
2085  ErrorLog(16, e.Message);
2086  }
2087 }
2088 
2089 // ---------------------------------------------------------------------------
2090 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2091 {
2092  try
2093  {
2094  TrainController->LogEvent("RouteCancelButtonClick");
2095  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2096  RouteCancelFlag = true;
2097  InfoPanel->Visible = true;
2098  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2099  RouteCancelButton->Enabled = false;
2100  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2101  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2102  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2103  Utilities->CallLogPop(1176);
2104  }
2105  catch(const Exception &e)
2106  {
2107  ErrorLog(35, e.Message);
2108  }
2109 }
2110 
2111 // ---------------------------------------------------------------------------
2112 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2113 {
2114  try
2115  {
2116  TrainController->LogEvent("PerformanceLogButtonClick");
2117  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2119  {
2120  ShowPerformancePanel = true;
2121  PerformancePanel->Visible = true;
2122  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2123  }
2124  else
2125  {
2126  ShowPerformancePanel = false;
2127  PerformancePanel->Visible = false;
2128  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2129  }
2130  Utilities->CallLogPop(1177);
2131  }
2132  catch(const Exception &e)
2133  {
2134  ErrorLog(36, e.Message);
2135  }
2136 }
2137 // ---------------------------------------------------------------------------
2138 
2139 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2140 {
2141  try
2142  {
2143  TrainController->LogEvent("ExitOperationButtonClick");
2144  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2146  {
2147  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2148  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2150  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2151  TrainController->BaseTime = TDateTime::CurrentDateTime();
2153  if(button == IDNO)
2154  {
2155  Utilities->CallLogPop(751);
2156  return;
2157  }
2158  }
2159  Track->ResetSignals(1);
2160  Track->ResetPoints(1);
2161  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2162  Utilities->PerformanceFile.close();
2165  RouteMode = None;
2166  PreferredRoute = true;
2167  ConsecSignalsRoute = true;
2169  ShowPerformancePanel = false;
2170  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2171  ShowOperatorActionPanel = false; // new at v2.2.0
2172  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2173  PerformanceLogBox->Lines->Clear();
2174  PerformancePanel->Visible = false;
2175  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2176  PerformancePanel->Left = MainScreen->Left;
2177 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2178  OAListBox->Clear();
2179  OperatorActionPanel->Visible = false;
2180  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2181  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ;
2183  AllRoutes->LockedRouteVector.clear();
2184  Level1Mode = BaseMode;
2185  SetLevel1Mode(8); // calls Clearand...
2186  Utilities->CallLogPop(1555);
2187  }
2188  catch(const Exception &e)
2189  {
2190  ErrorLog(13, e.Message);
2191  }
2192 }
2193 
2194 // ---------------------------------------------------------------------------
2195 // Menu Interface (for items not already covered above)
2196 // ---------------------------------------------------------------------------
2197 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2198 {
2199  try
2200  {
2201  TrainController->LogEvent("LoadRailwayMenuItemClick");
2202  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2203  if(!ClearEverything(1))
2204  {
2205  Utilities->CallLogPop(1139);
2206  return;
2207  }
2208  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2209  // changed at v2.0.0 (Embarcadero change) to show all files together
2210  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2211  if(LoadRailwayDialog->Execute())
2212  {
2213  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2214  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2215  }
2216  // else ShowMessage("Load Aborted"); drop this
2217  // Display->Update(); //display updated in ClearandRebuildRailway
2218  Track->CalcHLocMinEtc(9);
2219  Level1Mode = BaseMode;
2222  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2223  Utilities->CallLogPop(31);
2224  }
2225  catch(const Exception &e)
2226  {
2227  ErrorLog(17, e.Message);
2228  }
2229 }
2230 // ---------------------------------------------------------------------------
2231 
2232 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2233 { // display of the loaded railway covered in the calling routine
2234  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2235  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2236  {
2237  Screen->Cursor = TCursor(-11); // Hourglass;
2238  std::ifstream VecFile(LoadFileName.c_str());
2239  if(!(VecFile.fail()))
2240  {
2241  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2242  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2243  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2244  bool GraphicsFollow = false;
2245  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2246 // load track elements
2247  Track->LoadTrack(1, VecFile, GraphicsFollow);
2248 // load text elements
2249  TextHandler->LoadText(0, VecFile);
2250 // load PrefDir elements
2251  EveryPrefDir->LoadPrefDir(0, VecFile);
2252  if(GraphicsFollow)
2253  {
2254 // load user graphics
2255  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2256  }
2257  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2258  VecFile.close();
2259  Display->DisplayOffsetHHome = TempOffsetHHome;
2260  Display->DisplayOffsetVHome = TempOffsetVHome;
2262 
2263  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2264  TempFont->Style.Clear();
2265  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2266  TempFont->Size = 10;
2267  TempFont->Color = clB0G0R0;
2268  TempFont->Charset = (TFontCharset)(0);
2269  MainScreen->Canvas->Font->Assign(TempFont);
2270  delete TempFont;
2271 
2272 // calculate starting zoomed out offset values - same as when zoom out button clicked
2273  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2274 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2275  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2276  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2277  if((LeftExcess > 0) && (RightExcess > 0))
2278  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2279  else if((LeftExcess > 0) && (RightExcess <= 0))
2280  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2281  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2282  else if((LeftExcess <= 0) && (RightExcess > 0))
2283  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2284  else
2285  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2286 
2287  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2288  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2289  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2290  if((TopExcess > 0) && (BotExcess > 0))
2291  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2292  else if((TopExcess > 0) && (BotExcess <= 0))
2293  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2294  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2295  else if((TopExcess <= 0) && (BotExcess > 0))
2296  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2297  else
2298  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2299 // all above same as when zoom out button clicked
2300  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2302 
2303  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2304  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2305  {
2306  char LastChar = SavedFileName[SavedFileName.Length()];
2307  if((LastChar == 'y') || (LastChar == 'Y'))
2308  {
2309  if(!(Track->IsReadyForOperation()))
2310  {
2311  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2312  SavedFileName = "";
2313  RlyFile = false;
2314  RailwayTitle = "";
2315  TimetableTitle = "";
2316  SetCaption(5);
2317  Track->CalcHLocMinEtc(1);
2318  Screen->Cursor = TCursor(-2); // Arrow
2319  Level1Mode = BaseMode;
2320  SetLevel1Mode(9);
2321  Utilities->CallLogPop(1136);
2322  return;
2323  }
2324  else
2325  {
2326  RlyFile = true;
2327  }
2328  }
2329  else
2330  {
2331  RlyFile = false;
2332  }
2333  }
2334  else
2335  {
2336  RlyFile = false;
2337  }
2338  FileChangedFlag = false;
2339  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2340  {
2341  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2342  {
2343  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2344  TimetableTitle = "";
2345  SetCaption(6);
2346  break;
2347  }
2348  }
2349  } // if(VecFile)
2350  else
2351  ShowMessage("File open failed prior to load");
2352  Screen->Cursor = TCursor(-2); // Arrow
2353  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2354  else
2355  ShowMessage("File integrity check failed - unable to load");
2356  Utilities->CallLogPop(1774);
2357 }
2358 
2359 // ---------------------------------------------------------------------------
2360 
2361 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2362 {
2363 // save under existing name
2364 // no need to alter RlyFile for saving under existing name
2365 
2366  try
2367  {
2368  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2369  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2370  Screen->Cursor = TCursor(-11); // Hourglass;
2371  std::ofstream VecFile(SavedFileName.c_str());
2372  if(!(VecFile.fail()))
2373  {
2377  // save track elements
2378  if(Track->UserGraphicVector.empty())
2379  {
2380  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2381  }
2382  else
2383  {
2384  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2385  }
2386  // save text elements
2387  TextHandler->SaveText(0, VecFile);
2388  // save PrefDir elements
2389  EveryPrefDir->SavePrefDirVector(0, VecFile);
2390  if(!Track->UserGraphicVector.empty())
2391  {
2392  // save user graphics
2393  Track->SaveUserGraphics(0, VecFile);
2394  }
2395  FileChangedFlag = false;
2396  VecFile.close();
2397  }
2398  else
2399  ShowMessage("File open failed prior to save");
2400  Screen->Cursor = TCursor(-2); // Arrow
2401  Level1Mode = BaseMode;
2402  SetLevel1Mode(12); // to disable the save option
2403  Utilities->CallLogPop(1178);
2404  }
2405  catch(const Exception &e)
2406  {
2407  ErrorLog(135, e.Message);
2408  }
2409 }
2410 
2411 // ---------------------------------------------------------------------------
2412 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2413 {
2414  try
2415  {
2416  TrainController->LogEvent("SaveAsMenuItemClick");
2417  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2418  SaveAsSubroutine(0);
2419  Utilities->CallLogPop(32);
2420  }
2421  catch(const Exception &e)
2422  {
2423  ErrorLog(18, e.Message);
2424  }
2425 }
2426 
2427 // ---------------------------------------------------------------------------
2428 
2429 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2430 { // need to stop clock in case invoke during operation
2431  try
2432  {
2433  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2434  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2435  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2436  {
2437  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2438  Utilities->CallLogPop(1695);
2439  return;
2440  }
2441  Screen->Cursor = TCursor(-11); // Hourglass;
2442  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2444  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2445  // format "16/06/2009 20:55:17"
2446  // avoid characters in filename:= / \ : * ? " < > |
2447  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2448  AnsiString ShortName = "";
2449  for(int x = ImageFileName.Length(); x > 0; x--)
2450  {
2451  if(ImageFileName[x] == '\\')
2452  {
2453  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2454  break;
2455  }
2456  }
2457  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2458  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2459  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2460 
2461  int HPosMin = Track->GetHLocMin() * 16;
2462  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2463  int VPosMin = Track->GetVLocMin() * 16;
2464  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2465  RailwayImage->Width = HPosMax - HPosMin;
2466  RailwayImage->Height = VPosMax - VPosMin;
2467 
2468  // need to check if there is any text that extends past HPosMax or below VPosMax
2469  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2470  if(!TextHandler->TextVector.empty())
2471  {
2472  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2473  {
2474  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2475  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2476  if(NewWidth > RailwayImage->Width)
2477  {
2478  RailwayImage->Width = NewWidth;
2479  }
2480  if(NewHeight > RailwayImage->Height)
2481  {
2482  RailwayImage->Height = NewHeight;
2483  }
2484  }
2485  }
2486 
2487  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2488  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2489  RailwayImage->Canvas->FillRect(Rect);
2490 
2491  // write graphics first so text & track overwrite
2492  Track->WriteGraphicsToImage(0, RailwayImage);
2493  // then write text so track overwrites
2494  TextHandler->WriteTextToImage(0, RailwayImage);
2495  Track->WriteTrackToImage(0, RailwayImage);
2496 
2497  RailwayImage->SaveToFile(ImageFileName);
2498  delete RailwayImage;
2499  TrainController->BaseTime = TDateTime::CurrentDateTime();
2501  Screen->Cursor = TCursor(-2); // Arrow
2502  Utilities->CallLogPop(1535);
2503  }
2504  catch(const Exception &e)
2505  {
2506  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2507  {
2508  Screen->Cursor = TCursor(-2); // Arrow;
2509  UnicodeString MessageStr = "Insufficient memory available to store this image";
2510  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2511  }
2512  else
2513  {
2514  ErrorLog(42, e.Message);
2515  }
2516  }
2517 }
2518 
2519 // ---------------------------------------------------------------------------
2520 
2521 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2522 { // need to stop clock in case invoke during operation
2523  try
2524  {
2525  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2526  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2527  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2528  {
2529  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2530  Utilities->CallLogPop(1696);
2531  return;
2532  }
2533  Screen->Cursor = TCursor(-11); // Hourglass;
2534  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2536  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2537  // format "16/06/2009 20:55:17"
2538  // avoid characters in filename:= / \ : * ? " < > |
2539  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2540  AnsiString ShortName = "";
2541  for(int x = ImageFileName.Length(); x > 0; x--)
2542  {
2543  if(ImageFileName[x] == '\\')
2544  {
2545  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2546  break;
2547  }
2548  }
2549  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2550  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2551  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2552  int HPosMin = Track->GetHLocMin() * 16;
2553  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2554  int VPosMin = Track->GetVLocMin() * 16;
2555  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2556  RailwayImage->Width = HPosMax - HPosMin;
2557  RailwayImage->Height = VPosMax - VPosMin;
2558 
2559  // need to check if there is any text that extends past HPosMax or below VPosMax
2560  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2561  if(!TextHandler->TextVector.empty())
2562  {
2563  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2564  {
2565  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2566  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2567  if(NewWidth > RailwayImage->Width)
2568  {
2569  RailwayImage->Width = NewWidth;
2570  }
2571  if(NewHeight > RailwayImage->Height)
2572  {
2573  RailwayImage->Height = NewHeight;
2574  }
2575  }
2576  }
2577 
2578  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2579  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2580  RailwayImage->Canvas->FillRect(Rect);
2581 
2582  // write the grid first so all else on top
2583  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2584  {
2585  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2586  {
2587  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2588  }
2589  }
2590  // write graphics next so text & track overwrite
2591  Track->WriteGraphicsToImage(1, RailwayImage);
2592  // then write text so track overwrites
2593  TextHandler->WriteTextToImage(1, RailwayImage);
2594  Track->WriteTrackToImage(1, RailwayImage);
2595  RailwayImage->SaveToFile(ImageFileName);
2596  delete RailwayImage;
2597  TrainController->BaseTime = TDateTime::CurrentDateTime();
2599  Screen->Cursor = TCursor(-2); // Arrow
2600  Utilities->CallLogPop(1536);
2601  }
2602  catch(const Exception &e)
2603  {
2604  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2605  {
2606  Screen->Cursor = TCursor(-2); // Arrow;
2607  UnicodeString MessageStr = "Insufficient memory available to store this image";
2608  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2609  }
2610  else
2611  {
2612  ErrorLog(43, e.Message);
2613  }
2614  }
2615 }
2616 // ---------------------------------------------------------------------------
2617 
2618 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2619 { // need to stop clock in case invoke during operation
2620  try
2621  {
2622  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2623  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2624  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2625  {
2626  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2627  Utilities->CallLogPop(1697);
2628  return;
2629  }
2630  Screen->Cursor = TCursor(-11); // Hourglass;
2631  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2633  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2634  // format "16/06/2009 20:55:17"
2635  // avoid characters in filename:= / \ : * ? " < > |
2636  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2637  AnsiString ShortName = "";
2638  for(int x = ImageFileName.Length(); x > 0; x--)
2639  {
2640  if(ImageFileName[x] == '\\')
2641  {
2642  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2643  break;
2644  }
2645  }
2646  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2647  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2648  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2649  int HPosMin = Track->GetHLocMin() * 16;
2650  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2651  int VPosMin = Track->GetVLocMin() * 16;
2652  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2653  RailwayImage->Width = HPosMax - HPosMin;
2654  RailwayImage->Height = VPosMax - VPosMin;
2655 
2656  // need to check if there is any text that extends past HPosMax or below VPosMax
2657  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2658  if(!TextHandler->TextVector.empty())
2659  {
2660  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2661  {
2662  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2663  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2664  if(NewWidth > RailwayImage->Width)
2665  {
2666  RailwayImage->Width = NewWidth;
2667  }
2668  if(NewHeight > RailwayImage->Height)
2669  {
2670  RailwayImage->Height = NewHeight;
2671  }
2672  }
2673  }
2674 
2675  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2676  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2677  RailwayImage->Canvas->FillRect(Rect);
2678 
2679  // write graphics first so text & track overwrite
2680  Track->WriteGraphicsToImage(2, RailwayImage);
2681  // then write text so track overwrites
2682  TextHandler->WriteTextToImage(2, RailwayImage);
2683  Track->WriteTrackToImage(2, RailwayImage);
2684  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2685  RailwayImage->SaveToFile(ImageFileName);
2686  delete RailwayImage;
2687  TrainController->BaseTime = TDateTime::CurrentDateTime();
2689  Screen->Cursor = TCursor(-2); // Arrow
2690  Utilities->CallLogPop(1566);
2691  }
2692  catch(const Exception &e)
2693  {
2694  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2695  {
2696  Screen->Cursor = TCursor(-2); // Arrow;
2697  UnicodeString MessageStr = "Insufficient memory available to store this image";
2698  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2699  }
2700  else
2701  {
2702  ErrorLog(45, e.Message);
2703  }
2704  }
2705 }
2706 // ---------------------------------------------------------------------------
2707 
2708 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2709 { // need to stop clock
2710  try
2711  {
2712  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2713  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2714  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2715  {
2716  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2717  Utilities->CallLogPop(1702);
2718  return;
2719  }
2720  Screen->Cursor = TCursor(-11); // Hourglass;
2721  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2723 
2724  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
2725  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
2726  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2727  // format "16/06/2009 20:55:17"
2728  // avoid characters in filename:= / \ : * ? " < > |
2729  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
2730  "; " + TimetableTitle + ".bmp";
2731  AnsiString ShortName = "";
2732  for(int x = ImageFileName.Length(); x > 0; x--)
2733  {
2734  if(ImageFileName[x] == '\\')
2735  {
2736  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2737  break;
2738  }
2739  }
2740  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2741  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2742  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2743  int HPosMin = Track->GetHLocMin() * 16;
2744  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2745  int VPosMin = Track->GetVLocMin() * 16;
2746  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2747  RailwayImage->Width = HPosMax - HPosMin;
2748  RailwayImage->Height = VPosMax - VPosMin;
2749 
2750  // need to check if there is any text that extends past HPosMax or below VPosMax
2751  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2752  if(!TextHandler->TextVector.empty())
2753  {
2754  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2755  {
2756  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2757  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2758  if(NewWidth > RailwayImage->Width)
2759  {
2760  RailwayImage->Width = NewWidth;
2761  }
2762  if(NewHeight > RailwayImage->Height)
2763  {
2764  RailwayImage->Height = NewHeight;
2765  }
2766  }
2767  }
2768 
2769  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2770  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2771  RailwayImage->Canvas->FillRect(Rect);
2772 
2773  // write graphics first so text & track overwrite
2774  Track->WriteGraphicsToImage(3, RailwayImage);
2775  // then write text so track overwrites
2776  TextHandler->WriteTextToImage(3, RailwayImage);
2777  Track->WriteOperatingTrackToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
2778  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
2779 // add any locked route markers
2780  if(!AllRoutes->LockedRouteVector.empty())
2781  {
2782  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
2783  {
2784  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
2785  int x = Route.PrefDirSize() - 1;
2786  bool BreakFlag = false;
2787  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
2788  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
2789  {
2790  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2791  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2792  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
2793  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
2794  {
2795  BreakFlag = true;
2796  break; // train removed earlier element from route so stop here
2797  }
2798  x--;
2799  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
2800  }
2801  if(!BreakFlag)
2802  {
2803  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
2804  {
2805  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2806  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2807  }
2808  }
2809  }
2810  }
2811  TrainController->WriteTrainsToImage(0, RailwayImage);
2812  RailwayImage->SaveToFile(ImageFileName);
2813  delete RailwayImage;
2814  TrainController->BaseTime = TDateTime::CurrentDateTime();
2816  Screen->Cursor = TCursor(-2); // Arrow
2817  Utilities->CallLogPop(1703);
2818  }
2819  catch(const Exception &e)
2820  {
2821  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2822  {
2823  Screen->Cursor = TCursor(-2); // Arrow;
2824  UnicodeString MessageStr = "Insufficient memory available to store this image";
2825  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2826  }
2827  else
2828  {
2829  ErrorLog(113, e.Message); //NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
2830  }
2831  }
2832 }
2833 
2834 // ---------------------------------------------------------------------------
2835 
2836 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
2837 {
2838 //
2839  try
2840  {
2841  TrainController->LogEvent("SaveHeaderMenu1Click");
2842  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
2843  if(Sender == SaveSessionButton)
2844  {
2845  SaveSessionFlag = true;
2846  }
2847  else if(SavedFileName == "") // use 'Save As' function
2848  {
2849  SaveAsSubroutine(1);
2850  }
2851  else // ordinary save
2852  {
2853  Screen->Cursor = TCursor(-11); // Hourglass;
2854  std::ofstream VecFile(SavedFileName.c_str());
2855  if(!(VecFile.fail()))
2856  {
2860  // save track elements
2861  if(Track->UserGraphicVector.empty())
2862  {
2863  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2864  }
2865  else
2866  {
2867  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2868  }
2869  // save text elements
2870  TextHandler->SaveText(5, VecFile);
2871  // save PrefDir elements
2872  EveryPrefDir->SavePrefDirVector(8, VecFile);
2873  if(!Track->UserGraphicVector.empty())
2874  {
2875  // save user graphics
2876  Track->SaveUserGraphics(1, VecFile);
2877  }
2878  FileChangedFlag = false;
2879  VecFile.close();
2880  }
2881  else
2882  ShowMessage("Railway failed to save - can't open file");
2883  Screen->Cursor = TCursor(-2); // Arrow
2884  }
2885  Utilities->CallLogPop(1552);
2886  }
2887  catch(const Exception &e)
2888  {
2889  ErrorLog(44, e.Message);
2890  }
2891 }
2892 
2893 // ---------------------------------------------------------------------------
2894 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
2895 {
2896  try
2897  {
2898  TrainController->LogEvent("LoadSessionMenuItemClick");
2899  LoadSessionFlag = true; // load session within ClockTimer2
2900  }
2901  catch(const Exception &e)
2902  {
2903  ErrorLog(136, e.Message);
2904  }
2905 }
2906 
2907 // ---------------------------------------------------------------------------
2908 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
2909 {
2910  try
2911  {
2912  TrainController->LogEvent("ClearAllMenuItemClick");
2913  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
2914  if(ClearEverything(2))
2915  {;
2916  } // no change in action on result
2917  Level1Mode = BaseMode;
2918  SetLevel1Mode(126);
2919  Utilities->CallLogPop(1179);
2920  }
2921  catch(const Exception &e)
2922  {
2923  ErrorLog(137, e.Message);
2924  }
2925 }
2926 
2927 // ---------------------------------------------------------------------------
2928 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
2929 { // no need to stop clock as can't be called when railway operating
2930  try
2931  {
2932  TrainController->LogEvent("ExportTTMenuItemClick");
2933  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
2934  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
2935  {
2936  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
2937  Utilities->CallLogPop(1699);
2938  return;
2939  }
2940 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
2941 // the message instead, but reset here afterwards
2942  // no need to stop clock as can't select this if operating
2944  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
2945  Utilities->CallLogPop(1573);
2946  }
2947  catch(const Exception &e)
2948  {
2949  ErrorLog(138, e.Message);
2950  }
2951 }
2952 // ---------------------------------------------------------------------------
2953 // Timetable editing functions
2954 
2955 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
2956  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
2957  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
2958  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
2959  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
2960 
2961  CR & LF review:
2962  These cause problems by the way that different subroutines handle them.
2963 
2964  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
2965 
2966  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
2967  (a) n-1 characters are stored + '\0' after the n-1 characters;
2968  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
2969  precedes the CRLF in the stream; and
2970  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
2971  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
2972 
2973  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
2974  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
2975 
2976 */
2977 // ---------------------------------------------------------------------------
2978 
2979 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
2980 {
2981  try
2982  {
2983  TrainController->LogEvent("CreateTimetableMenuItemClick");
2984  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
2985  CreateEditTTFileName = "";
2986  TimetableEditVector.clear();
2987  TimetableEditPanel->Visible = true;
2988  HighlightPanel->Visible = false;
2989  TimetablePanel->Visible = true;
2990  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
2991  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
2992  OneEntryTimetableMemo->Clear();
2993  AllEntriesTTListBox->Clear();
2994  TTStartTimeBox->Text = "";
2995  AddSubMinsBox->Text = "";
2997  LocationNameComboBox->Clear();
2998  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
2999  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
3000  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3001  TimetableChangedFlag = false;
3002  TimetableValidFlag = false;
3003  TTEntryChangedFlag = false;
3005  AZOrderButton->Caption = AnsiString("A-Z Order");
3006  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3007  CopiedEntryFlag = false;
3008  NewEntryInPreparationFlag = false;
3009  CopiedEntryStr = "";
3010  TEVPtr = 0;
3012  TTFirstServicePtr = 0;
3013  TTLastServicePtr = 0; // all set to null to begin with
3014 
3015 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3016  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3018  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3019  {
3020  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3021  == Track->ContinuationNameMap.end())
3022  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3023  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3024  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3025  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3026  }
3027  }
3029  if(!(Track->ActiveTrackElementNameMap.empty()))
3030  {
3031  LocationNameComboBox->Text = "Location names";
3032 // new version at beta v0.2b
3034  ATENIT++)
3035  {
3036  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3037  // continuations as well as other track will be included - earlier version
3038  // would have excluded them
3039  }
3040 
3041 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3042  locations
3043  TStringList *StringList = new TStringList;
3044  StringList->Clear();//probably already empty but help file doesn't say so
3045  StringList->Sorted = false;//for now
3046  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3047  {
3048  NewKey = LNMIT->first;
3049  if(OldKey != NewKey)//only add new values
3050  {
3051  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3052  {
3053  StringList->Add(NewKey);
3054  OldKey = NewKey;
3055  }
3056  }
3057  }
3058  StringList->Sort();
3059  for(int x=0;x<StringList->Count;x++)
3060  {
3061  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3062  }
3063  delete StringList;
3064 */
3065  }
3066  else
3067  {
3068  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3069  }
3071  SetLevel1Mode(82);
3072  Utilities->CallLogPop(1595);
3073  }
3074  catch(const Exception &e)
3075  {
3076  ErrorLog(47, e.Message);
3077  }
3078 }
3079 
3080 // ---------------------------------------------------------------------------
3081 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3082 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3083  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3084 */
3085 {
3086  try
3087  {
3088  TrainController->LogEvent("EditTimetableMenuItemClick");
3089  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3090  SigImagePanel->Visible = false; //stop panel showing while waiting for name entry
3091  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3092  CreateEditTTFileName = "";
3093  TimetableEditVector.clear();
3094  TimetableEditPanel->Visible = true;
3095  HighlightPanel->Visible = false;
3096  TimetablePanel->Visible = true;
3097  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3098  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3099  OneEntryTimetableMemo->Clear();
3100  AllEntriesTTListBox->Clear();
3101  TTStartTimeBox->Text = "";
3102  AddSubMinsBox->Text = "";
3104  LocationNameComboBox->Clear();
3105  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3106  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3107  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3108  TEVPtr = 0;
3110  TTFirstServicePtr = 0;
3111  TTLastServicePtr = 0; // all set to null to begin with
3112  if(TimetableDialog->Execute())
3113  {
3114  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3115  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3116  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3117  if(TTBLFile.is_open())
3118  {
3119  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3120  char c;
3121  while(!TTBLFile.eof())
3122  {
3123  TTBLFile.get(c);
3124  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3125  {
3126  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3127  TTBLFile.close();
3128  Utilities->CallLogPop(1612);
3129  return;
3130  }
3131  }
3132  TTBLFile.close();
3133  }
3134  else
3135  {
3136  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3137  Utilities->CallLogPop(1597);
3138  return;
3139  }
3140  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3141  Delay(4, 100); // 100mSec delay between closing & re-opening file
3142  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3143  if(TTBLFile.is_open())
3144  {
3145  TTBLFile.clear(); // to clear eofbit from last read
3146  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3147  TimetableChangedFlag = false;
3148  TimetableValidFlag = false;
3149  TTEntryChangedFlag = false;
3151  AZOrderButton->Caption = AnsiString("A-Z Order");
3152  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3153  NewEntryInPreparationFlag = false;
3154  CopiedEntryStr = "";
3155  CopiedEntryFlag = false;
3156 // CreateEditTTFileName = TimetableDialog->FileName;
3157  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3158  {
3159  if(CreateEditTTFileName[x] == '\\')
3160  {
3161  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3162  break;
3163  }
3164  }
3165  char *TimetableEntryString = new char[10000];
3166  while(true)
3167  {
3168  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3169  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3170  { // may still have eof even if read a line, and
3171  // if so need to process it
3172  break;
3173  }
3174  AnsiString OneLine(TimetableEntryString);
3175  TimetableEditVector.push_back(OneLine);
3176  }
3177  TTBLFile.close();
3178  delete TimetableEntryString;
3179  // here with TimetableEditVector compiled
3180  }
3181  else
3182  {
3183  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3184  Utilities->CallLogPop(1654);
3185  return;
3186  }
3187  }
3188  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3189  {
3190  CreateEditTTFileName = "";
3191 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3192  CreateEditTTTitle = ""; // as above
3193  Level1Mode = BaseMode;
3194  SetLevel1Mode(132);
3195  Utilities->CallLogPop(1633);
3196  return;
3197  }
3198 
3200  if(TimetableEditVector.empty())
3201  {
3203  SetLevel1Mode(89);
3204  Utilities->CallLogPop(1614);
3205  return;
3206  }
3207 
3208 // all now set where can be
3210 
3211 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3212  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3214  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3215  {
3216  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3217  == Track->ContinuationNameMap.end())
3218  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3219  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3220  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3221  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3222  }
3223  }
3225  if(!(Track->ActiveTrackElementNameMap.empty()))
3226  {
3227  LocationNameComboBox->Text = "Location names";
3228 // new version for beta v0.2b
3230  ATENIT++)
3231  {
3232  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3233  // continuations as well as other track will be included - earlier version
3234  // would have excluded them
3235  }
3236  }
3237  else
3238  {
3239  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3240  }
3242  SetLevel1Mode(83);
3243  Utilities->CallLogPop(1596);
3244  }
3245  catch(const Exception &e)
3246  {
3247  ErrorLog(48, e.Message);
3248  }
3249 }
3250 // ---------------------------------------------------------------------------
3251 
3252 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3253 {
3254  try
3255  {
3256  TrainController->LogEvent("ShowHideTTButtonClick");
3257  if(TimetableEditPanel->Visible)
3258  {
3259  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3260  TimetableEditPanel->Visible = false;
3261  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3262 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3263  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3264  }
3265  else
3266  {
3267  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3268  TimetableEditPanel->Visible = true;
3269  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3271  SetLevel1Mode(124);
3272  }
3273  }
3274  catch(const Exception &e)
3275  {
3276  ErrorLog(139, e.Message);
3277  }
3278 }
3279 // ---------------------------------------------------------------------------
3280 
3281 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3282 {
3283  try
3284  {
3285  TrainController->LogEvent("NextTTEntryButtonClick");
3286  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3287  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3288  {
3289  Utilities->CallLogPop(1683);
3290  return;
3291  }
3292  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3294  TTEntryChangedFlag = false;
3295  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3296  // position changing in AllEntriesTTListBox
3298  SetLevel1Mode(85);
3299  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3300  {
3302  }
3303  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3304  {
3305  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3306  }
3307  else
3308  {
3309  AllEntriesTTListBox->TopIndex = TopPos;
3310  }
3311  Utilities->CallLogPop(1605);
3312  }
3313  catch(const Exception &e)
3314  {
3315  ErrorLog(50, e.Message);
3316  }
3317 }
3318 
3319 // ---------------------------------------------------------------------------
3320 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3321 {
3322  try
3323  {
3324  TrainController->LogEvent("PreviousTTEntryButtonClick");
3325  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3326  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3327  {
3328  Utilities->CallLogPop(1684);
3329  return;
3330  }
3333  TTEntryChangedFlag = false;
3334  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3335  // position changing in AllEntriesTTListBox
3337  SetLevel1Mode(86);
3338  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3339  {
3341  }
3342  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3343  {
3344  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3345  }
3346  else
3347  {
3348  AllEntriesTTListBox->TopIndex = TopPos;
3349  }
3350  Utilities->CallLogPop(1607);
3351  }
3352  catch(const Exception &e)
3353  {
3354  ErrorLog(51, e.Message);
3355  }
3356 }
3357 
3358 // ---------------------------------------------------------------------------
3359 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3360 {
3361  try
3362  {
3363  TrainController->LogEvent("NewTTEntryButtonClick");
3364  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3365  OneEntryTimetableMemo->Clear();
3366  OneEntryTimetableMemo->SetFocus();
3369  SetLevel1Mode(103);
3370  Utilities->CallLogPop(1615);
3371  }
3372  catch(const Exception &e)
3373  {
3374  ErrorLog(52, e.Message);
3375  }
3376 }
3377 // ---------------------------------------------------------------------------
3378 
3379 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3380 {
3381  try
3382  {
3383  TrainController->LogEvent("AddMinsButtonClick");
3384  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3385  bool ValidFlag = true;
3386  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3387  {
3388  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3389  {
3390  ValidFlag = false;
3391  break;
3392  }
3393  }
3394  if(ValidFlag)
3395  {
3396  if(AddSubMinsBox->Text.ToInt() == 0)
3397  ValidFlag = false;
3398  }
3399  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3400  {
3401  Utilities->CallLogPop(1649);
3402  return;
3403  }
3404  TDateTime DummyTime;
3405  int AddMins = AddSubMinsBox->Text.ToInt();
3406  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3407  {
3408  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3409  {
3410  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3411  {
3412  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3413  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3414  Mins += AddMins;
3415  while(Mins >= 60)
3416  {
3417  Mins -= 60;
3418  Hrs++;
3419  }
3420  if(Hrs > 95)
3421  {
3422  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3423  Utilities->CallLogPop(1650);
3424  return;
3425  }
3426  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3427  if(Mins < 10)
3428  MinsStr = "0" + MinsStr;
3429  if(Hrs < 10)
3430  HrsStr = "0" + HrsStr;
3431  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3432  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3433  NewString += HrsStr + ':' + MinsStr;
3434  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3435  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3436  }
3437  }
3438  }
3439 
3440  OneEntryTimetableMemo->HideSelection = true;
3441  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3442  OneEntryTimetableMemo->SelLength = 0;
3443  TimetableValidFlag = false;
3444  TimetableChangedFlag = true;
3445  TTEntryChangedFlag = true;
3447  SetLevel1Mode(91);
3448  Utilities->CallLogPop(1617);
3449  }
3450  catch(const Exception &e)
3451  {
3452  ErrorLog(54, e.Message);
3453  }
3454 }
3455 // ---------------------------------------------------------------------------
3456 
3457 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3458 {
3459  try
3460  {
3461  TrainController->LogEvent("SubMinsButtonClick");
3462  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3463  bool ValidFlag = true;
3464  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3465  {
3466  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3467  {
3468  ValidFlag = false;
3469  break;
3470  }
3471  }
3472  if(ValidFlag)
3473  {
3474  if(AddSubMinsBox->Text.ToInt() == 0)
3475  ValidFlag = false;
3476  }
3477  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3478  {
3479  Utilities->CallLogPop(1659);
3480  return;
3481  }
3482  TDateTime DummyTime;
3483  int SubMins = AddSubMinsBox->Text.ToInt();
3484  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3485  {
3486  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3487  {
3488  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3489  {
3490  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3491  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3492  Mins -= SubMins;
3493  while(Mins < 0)
3494  {
3495  Mins += 60;
3496  Hrs--;
3497  }
3498  if(Hrs < 0)
3499  {
3500  ShowMessage("One or more times are now before 00:00, this is not permitted");
3501  Utilities->CallLogPop(1660);
3502  return;
3503  }
3504  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3505  if(Mins < 10)
3506  MinsStr = "0" + MinsStr;
3507  if(Hrs < 10)
3508  HrsStr = "0" + HrsStr;
3509  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3510  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3511  NewString += HrsStr + ':' + MinsStr;
3512  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3513  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3514  }
3515  }
3516  }
3517  OneEntryTimetableMemo->HideSelection = true;
3518  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3519  OneEntryTimetableMemo->SelLength = 0;
3520  TimetableValidFlag = false;
3521  TimetableChangedFlag = true;
3522  TTEntryChangedFlag = true;
3524  SetLevel1Mode(92);
3525  Utilities->CallLogPop(1618);
3526  }
3527  catch(const Exception &e)
3528  {
3529  ErrorLog(55, e.Message);
3530  }
3531 }
3532 // ---------------------------------------------------------------------------
3533 
3534 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3535 {
3536  try
3537  {
3538  TrainController->LogEvent("CopyTTEntryButtonClick");
3539  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3540  if(TTCurrentEntryPtr == 0)
3541  {
3542  Utilities->CallLogPop(1636);
3543  return;
3544  }
3546  CopiedEntryFlag = true;
3547  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3548  // position changing in AllEntriesTTListBox
3550  SetLevel1Mode(93);
3551  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3552  {
3554  }
3555  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3556  {
3557  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3558  }
3559  else
3560  {
3561  AllEntriesTTListBox->TopIndex = TopPos;
3562  }
3563  Utilities->CallLogPop(1619);
3564  }
3565  catch(const Exception &e)
3566  {
3567  ErrorLog(56, e.Message);
3568  }
3569 }
3570 // ---------------------------------------------------------------------------
3571 
3572 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3573 {
3574  try
3575  {
3576  TrainController->LogEvent("CutTTEntryButtonClick");
3577  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3578  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3579  {
3580  Utilities->CallLogPop(1674);
3581  return;
3582  }
3584  CopiedEntryFlag = true;
3585  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3586  // so use the position in the vector
3588 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3589 // pick up the start time if there is one
3590  TimetableChangedFlag = true;
3591  TimetableValidFlag = false;
3592  TTEntryChangedFlag = false;
3593  TEVPtr = 0;
3595  TTFirstServicePtr = 0;
3596  TTLastServicePtr = 0; // all set to null to begin with
3597  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3598  // position changing in AllEntriesTTListBox
3599  AllEntriesTTListBox->Clear();
3601  if(TimetableEditVector.empty())
3602  {
3604  SetLevel1Mode(109);
3605  Utilities->CallLogPop(1777);
3606  return;
3607  }
3608 
3609 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed after v2.4.3
3610 // but vector pointers unreliable after an erase, so use the position in the vector
3611  if(OldVectorPos == 0)
3612  {
3614  }
3615  else
3616  {
3617  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3618  }
3619  if(TTCurrentEntryPtr == 0)
3620  {
3621  OneEntryTimetableMemo->Clear();
3622  }
3624  SetLevel1Mode(115);
3625  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3626  {
3628  }
3629  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3630  {
3631  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3632  }
3633  else
3634  {
3635  AllEntriesTTListBox->TopIndex = TopPos;
3636  }
3637  Utilities->CallLogPop(1676);
3638  }
3639  catch(const Exception &e)
3640  {
3641  ErrorLog(111, e.Message);
3642  }
3643 }
3644 
3645 // ---------------------------------------------------------------------------
3646 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3647 {
3648  try
3649  {
3650  TrainController->LogEvent("PasteTTEntryButtonClick");
3651  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3652  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3653  {
3654  Utilities->CallLogPop(1637);
3655  return;
3656  }
3657  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3658  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3659  // after the current Entry - may be at the end
3660  TimetableChangedFlag = true;
3661  TimetableValidFlag = false;
3662  TTEntryChangedFlag = false;
3663  TEVPtr = 0;
3665  TTFirstServicePtr = 0;
3666  TTLastServicePtr = 0; // all set to null to begin with
3667  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3668  // position changing in AllEntriesTTListBox
3669  AllEntriesTTListBox->Clear();
3671  if(TimetableEditVector.empty())
3672  {
3674  SetLevel1Mode(110);
3675  Utilities->CallLogPop(1778);
3676  return;
3677  }
3678 // restore TTCurrentEntryPtr
3679  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3680  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3681 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3683  SetLevel1Mode(94);
3684  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3685  {
3687  }
3688  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3689  {
3690  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3691  }
3692  else
3693  {
3694  AllEntriesTTListBox->TopIndex = TopPos;
3695  }
3696  Utilities->CallLogPop(1620);
3697  }
3698  catch(const Exception &e)
3699  {
3700  ErrorLog(57, e.Message);
3701  }
3702 }
3703 // ---------------------------------------------------------------------------
3704 
3705 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
3706 {
3707  try
3708  {
3709  TrainController->LogEvent("DeleteTTEntryButtonClick");
3710  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
3711  if(TTCurrentEntryPtr == 0)
3712  {
3713  Utilities->CallLogPop(1645);
3714  return;
3715  }
3716  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
3717  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
3718  if(button == IDNO)
3719  {
3720  Utilities->CallLogPop(1663);
3721  return;
3722  }
3723  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3724  // so use the position in the vector
3726 
3727 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3728 // pick up the start time if there is one
3729  TimetableChangedFlag = true;
3730  TimetableValidFlag = false;
3731  TTEntryChangedFlag = false;
3732  TEVPtr = 0;
3734  TTFirstServicePtr = 0;
3735  TTLastServicePtr = 0; // all set to null to begin with
3736  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3737  // position changing in AllEntriesTTListBox
3738  AllEntriesTTListBox->Clear();
3740  if(TimetableEditVector.empty())
3741  {
3743  SetLevel1Mode(111);
3744  Utilities->CallLogPop(1779);
3745  return;
3746  }
3747 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
3748 // but vector pointers unreliable after an erase, so use the position in the vector
3749  if(OldVectorPos == 0)
3750  {
3752  }
3753  else
3754  {
3755  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3756  }
3757  if(TTCurrentEntryPtr == 0)
3758  {
3759  OneEntryTimetableMemo->Clear();
3760  }
3762  SetLevel1Mode(95);
3763  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3764  {
3766  }
3767  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3768  {
3769  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3770  }
3771  else
3772  {
3773  AllEntriesTTListBox->TopIndex = TopPos;
3774  }
3775  Utilities->CallLogPop(1621);
3776  }
3777  catch(const Exception &e)
3778  {
3779  ErrorLog(58, e.Message);
3780  }
3781 }
3782 // ---------------------------------------------------------------------------
3783 
3784 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
3785 {
3786  try
3787  {
3788  TrainController->LogEvent("SaveTTEntryButtonClick");
3789  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
3790 /* allow blank lines to be saved
3791  AnsiString ContentStr = OneEntryTimetableMemo->Text;
3792  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
3793  {
3794  Utilities->CallLogPop(1679);
3795  return;
3796  }
3797 */
3798  AnsiString TempStr = "";
3799  bool ActiveLine = false;
3800  if(TTCurrentEntryPtr > 0)
3801  {
3802  if(*TTCurrentEntryPtr != "")
3803  {
3805  {
3806  ActiveLine = true;
3807  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
3808  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3809  {
3810  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
3811  {
3812  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
3813  }
3814  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
3815  {
3816  TempStr += ',';
3817  }
3818  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
3819  // ends the timetable
3820  }
3821  // strip any excess commas from the end
3822  if(TempStr != "")
3823  {
3824  while(TempStr[TempStr.Length()] == ',')
3825  {
3826  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
3827  if(TempStr == "")
3828  break;
3829  }
3830  }
3831  }
3832  }
3833  }
3834  if(!ActiveLine)
3835  {
3836  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
3837  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
3838  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
3839  // and before a blank line or end of file, so the syntax check will work OK
3840  }
3841  if(AZOrderButton->Caption == AnsiString("Original Order"))
3842  {
3844  }
3845  TimetableValidFlag = false;
3846  TimetableChangedFlag = true;
3847  TTEntryChangedFlag = false;
3848  int TopPos;
3849  if(TTCurrentEntryPtr == 0)
3850  {
3852  }
3854  {
3855  (*TTCurrentEntryPtr) = TempStr;
3856  // need to reset the AllEntriesTTListBox in case the headcode has changed
3857  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3858  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3859  // position changing in AllEntriesTTListBox
3860  AllEntriesTTListBox->Clear();
3862  if(TimetableEditVector.empty())
3863  {
3865  SetLevel1Mode(112);
3866  Utilities->CallLogPop(1780);
3867  return;
3868  }
3869  // restore TTCurrentEntryPtr
3870  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3871  }
3872  else
3873  {
3874  NewEntryInPreparationFlag = false;
3875  if(TTCurrentEntryPtr != 0)
3876  {
3877  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3878  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
3879  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3881  }
3882  else
3883  {
3884  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
3886  }
3887  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
3888  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3889  // position changing in AllEntriesTTListBox
3890  AllEntriesTTListBox->Clear();
3892  if(TimetableEditVector.empty())
3893  {
3895  SetLevel1Mode(113);
3896  Utilities->CallLogPop(1781);
3897  return;
3898  }
3899 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
3900  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
3901  {
3903  }
3904  else
3905  {
3906  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3907  }
3908  }
3910  SetLevel1Mode(96);
3911  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3912  {
3914  }
3915  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3916  {
3917  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3918  }
3919  else
3920  {
3921  AllEntriesTTListBox->TopIndex = TopPos;
3922  }
3923  Utilities->CallLogPop(1622);
3924  }
3925  catch(const Exception &e)
3926  {
3927  ErrorLog(59, e.Message);
3928  }
3929 }
3930 // ---------------------------------------------------------------------------
3931 
3932 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
3933 {
3934  try
3935  {
3936  TrainController->LogEvent("SaveTTButtonClick");
3937  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
3938  if(TimetableEditVector.empty())
3939  {
3940  ShowMessage("Timetable is empty, can't save an empty timetable");
3941  Utilities->CallLogPop(1685);
3942  return;
3943  }
3944  std::ofstream TTBLFile;
3945  if(CreateEditTTFileName != "")
3946  {
3947  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
3948  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
3949  }
3950  else
3951  {
3952  if(SaveTTDialog->Execute())
3953  {
3954  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
3955  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3956  {
3957  if(CreateEditTTFileName[x] == '\\')
3958  {
3959  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3960  break;
3961  }
3962  }
3963  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
3964  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
3965  }
3966  else //cancelled dialog
3967  {
3969  SetLevel1Mode(137);
3970  Utilities->CallLogPop(2205);
3971  return;
3972  }
3973  }
3974  if(TTBLFile.is_open())
3975  {
3976  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
3977  {
3978  TTBLFile << (*TEVPtr).c_str() << '\0';
3979  }
3980  TimetableChangedFlag = false;
3981  TTBLFile.close();
3982  }
3983  else
3984  {
3985  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
3986  }
3988  SetLevel1Mode(97);
3989  Utilities->CallLogPop(1623);
3990  }
3991  catch(const Exception &e)
3992  {
3993  ErrorLog(60, e.Message);
3994  }
3995 }
3996 // ---------------------------------------------------------------------------
3997 
3998 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
3999 {
4000  try
4001  {
4002  TrainController->LogEvent("SaveTTAsButtonClick");
4003  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4004  if(TimetableEditVector.empty())
4005  {
4006  ShowMessage("Timetable is empty, can't save an empty timetable");
4007  Utilities->CallLogPop(1686);
4008  return;
4009  }
4010  std::ofstream TTBLFile;
4011  if(SaveTTDialog->Execute())
4012  {
4013  CreateEditTTFileName = SaveTTDialog->FileName;
4014  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4015  {
4016  if(SaveTTDialog->FileName[x] == '\\')
4017  {
4018  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4019  break;
4020  }
4021  }
4022  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4023  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4024  }
4025  else //cancelled dialog
4026  {
4028  SetLevel1Mode(138);
4029  Utilities->CallLogPop(2206);
4030  return;
4031  }
4032  if(TTBLFile.is_open())
4033  {
4034  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4035  {
4036  TTBLFile << (*TEVPtr).c_str() << '\0';
4037  }
4038  TimetableChangedFlag = false;
4039  TTBLFile.close();
4040  }
4041  else
4042  {
4043  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4044  }
4046  SetLevel1Mode(117);
4047  Utilities->CallLogPop(1667);
4048  }
4049  catch(const Exception &e)
4050  {
4051  ErrorLog(108, e.Message);
4052  }
4053 }
4054 // ---------------------------------------------------------------------------
4055 
4056 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4057 {
4058  try
4059  {
4060  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4061  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4062  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4063  bool EndOfFile = false;
4064  bool FinalCallFalse = false;
4065  bool GiveMessagesTrue = true;
4066  bool CheckLocationsExistInRailway = false;
4067  if(RlyFile)
4068  CheckLocationsExistInRailway = true;
4069 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4070  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4071  // return true for success
4072  {
4073  ShowMessage(
4074  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4075  }
4077  SetLevel1Mode(98);
4078  Utilities->CallLogPop(1624);
4079  }
4080  catch(const Exception &e)
4081  {
4082  ErrorLog(61, e.Message);
4083  }
4084 }
4085 // ---------------------------------------------------------------------------
4086 
4087 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4088 {
4089  try
4090  {
4091  TrainController->LogEvent("ValidateTimetableButtonClick");
4092  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4093  // reset all message flags, stops them being given twice new at v2.4.0
4094  TrainController->SSHigh = false;
4095  TrainController->MRSHigh = false;
4096  TrainController->MRSLow = false;
4097  TrainController->MassHigh = false;
4098  TrainController->BFHigh = false;
4099  TrainController->BFLow = false;
4100  TrainController->PwrHigh = false;
4101  TrainController->SigSHigh = false;
4102  TrainController->SigSLow = false;
4103  if(CreateEditTTFileName == "")
4104  {
4105  Utilities->CallLogPop(1664);
4106  return;
4107  }
4108  bool CheckLocationsExistInRailwayTrue = true;
4109  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4110  {
4111  Screen->Cursor = TCursor(-11); // Hourglass;
4112  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4113  if(TTBLFile.is_open())
4114  {
4115  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4116  {
4117  ShowMessage("Timetable integrity OK");
4118  TimetableValidFlag = true;
4119 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4120  };
4121  }
4122  else
4123  {
4124  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4125  }
4126  Screen->Cursor = TCursor(-2); // Arrow
4127  } // if(TimetableIntegrityCheck
4128  else
4129  {
4130 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4131  }
4133  SetLevel1Mode(99);
4134  Utilities->CallLogPop(1625);
4135  }
4136  catch(const Exception &e)
4137  {
4138  ErrorLog(62, e.Message);
4139  }
4140 }
4141 
4142 // ---------------------------------------------------------------------------
4143 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4144 {
4145  try
4146  {
4147  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4148  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4149  if(TTCurrentEntryPtr == 0)
4150  {
4151  Utilities->CallLogPop(1634);
4152  return;
4153  }
4154  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4155  {
4156  Utilities->CallLogPop(1632);
4157  return;
4158  }
4159  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4160  AnsiString TempStr = *TEVPtr;
4162  *TTCurrentEntryPtr = TempStr;
4164  TimetableChangedFlag = true;
4165  TimetableValidFlag = false;
4166 
4167 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4168  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4169  // position changing in AllEntriesTTListBox
4170  AllEntriesTTListBox->Clear();
4171  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4173 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4174  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4175  {
4177  }
4178  else
4179  {
4180  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4181  }
4183  SetLevel1Mode(100);
4184  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4185  {
4187  }
4188  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4189  {
4190  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4191  }
4192  else
4193  {
4194  AllEntriesTTListBox->TopIndex = TopPos;
4195  }
4196  Utilities->CallLogPop(1626);
4197  }
4198  catch(const Exception &e)
4199  {
4200  ErrorLog(63, e.Message);
4201  }
4202 }
4203 // ---------------------------------------------------------------------------
4204 
4205 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4206 {
4207  try
4208  {
4209  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4210  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4211  if(TTCurrentEntryPtr == 0)
4212  {
4213  Utilities->CallLogPop(1635);
4214  return;
4215  }
4216  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4217  {
4218  Utilities->CallLogPop(1678);
4219  return;
4220  }
4221  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4222  AnsiString TempStr = *TEVPtr;
4224  *TTCurrentEntryPtr = TempStr;
4226  TimetableChangedFlag = true;
4227  TimetableValidFlag = false;
4228 
4229 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4230  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4231  // position changing in AllEntriesTTListBox
4232  AllEntriesTTListBox->Clear();
4233  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4235 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4236  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4237  {
4239  }
4240  else
4241  {
4242  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4243  }
4245  SetLevel1Mode(101);
4246  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4247  {
4249  }
4250  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4251  {
4252  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4253  }
4254  else
4255  {
4256  AllEntriesTTListBox->TopIndex = TopPos;
4257  }
4258  Utilities->CallLogPop(1627);
4259  }
4260  catch(const Exception &e)
4261  {
4262  ErrorLog(64, e.Message);
4263  }
4264 }
4265 
4266 // ---------------------------------------------------------------------------
4267 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4268 {
4269  try
4270  {
4271  TrainController->LogEvent("CancelTTActionButtonClick");
4272  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4273  TTEntryChangedFlag = false;
4275  {
4276  NewEntryInPreparationFlag = false;
4277  OneEntryTimetableMemo->Clear();
4278  }
4279  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4280  // position changing in AllEntriesTTListBox
4282  SetLevel1Mode(102);
4283  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4284  {
4286  }
4287  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4288  {
4289  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4290  }
4291  else
4292  {
4293  AllEntriesTTListBox->TopIndex = TopPos;
4294  }
4295  Utilities->CallLogPop(1630);
4296  }
4297  catch(const Exception &e)
4298  {
4299  ErrorLog(102, e.Message);
4300  }
4301 }
4302 
4303 // ---------------------------------------------------------------------------
4304 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4305 {
4306  try
4307  {
4308  TrainController->LogEvent("RestoreTTButtonClick");
4309  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4311  {
4312  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4313  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4314  if(button == IDNO)
4315  {
4316  Utilities->CallLogPop(1651);
4317  return;
4318  }
4319  }
4320 
4321  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4322  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4323  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4324  if(TTBLFile.is_open())
4325  {
4326  TimetableChangedFlag = false;
4327  TimetableValidFlag = false;
4328  TTEntryChangedFlag = false;
4329  NewEntryInPreparationFlag = false;
4330  CopiedEntryFlag = false;
4331  CopiedEntryStr = "";
4332  TimetableEditVector.clear();
4333  OneEntryTimetableMemo->Clear();
4334  AllEntriesTTListBox->Clear();
4335  TTStartTimeBox->Text = "";
4336  AddSubMinsBox->Text = "";
4337  TEVPtr = 0;
4339  TTFirstServicePtr = 0;
4340  TTLastServicePtr = 0; // all set to null to begin with
4341  char *TimetableEntryString = new char[10000];
4342  while(true)
4343  {
4344  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4345  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4346  { // may still have eof even if read a line, and
4347  // if so need to process it
4348  break;
4349  }
4350  AnsiString OneLine(TimetableEntryString);
4351  TimetableEditVector.push_back(OneLine);
4352  }
4353  TTBLFile.close();
4354  delete TimetableEntryString;
4355  // here with TimetableEditVector compiled
4356  }
4357  else
4358  {
4359  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4360  Utilities->CallLogPop(1655);
4361  return;
4362  }
4363 
4365  if(TimetableEditVector.empty())
4366  {
4368  SetLevel1Mode(114);
4369  Utilities->CallLogPop(1782);
4370  return;
4371  }
4372 // all now set where can be
4374 // end of repeat from EditTimetableMenuItemClick
4375 
4377  SetLevel1Mode(104);
4378  Utilities->CallLogPop(1652);
4379  }
4380  catch(const Exception &e)
4381  {
4382  ErrorLog(104, e.Message);
4383  }
4384 }
4385 
4386 // ---------------------------------------------------------------------------
4387 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4388 {
4389  try
4390  {
4391  TrainController->LogEvent("ExportTTButtonClick");
4392  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4393  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4394  {
4395  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4396  Utilities->CallLogPop(1698);
4397  return;
4398  }
4399 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4400 // the message instead, but reset here afterwards
4401  AnsiString TTTitle;
4403  {
4404  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4405  {
4406  if(CreateEditTTFileName[x] == '\\')
4407  {
4408  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4409  break;
4410  }
4411  }
4413  }
4414  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4416  SetLevel1Mode(116);
4417  Utilities->CallLogPop(1662);
4418  }
4419  catch(const Exception &e)
4420  {
4421  ErrorLog(107, e.Message);
4422  }
4423 }
4424 
4425 // ---------------------------------------------------------------------------
4426 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4427 {
4428  try
4429  {
4430  TrainController->LogEvent("TTTextButtonClick");
4431  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4432 /*
4433  if(TTStartTimePtr == 0)
4434  {
4435  OneEntryTimetableMemo->Clear();
4436  TTStartTimeBox->SetFocus();
4437  Utilities->CallLogPop(1673);
4438  return;
4439  }
4440 */
4441  int SelPos = OneEntryTimetableMemo->SelStart;
4442  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4443  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4444  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4445  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4446  TTEntryChangedFlag = true;
4447  OneEntryTimetableMemo->SetFocus();
4449  SetLevel1Mode(119);
4450  Utilities->CallLogPop(1672);
4451  }
4452  catch(const Exception &e)
4453  {
4454  ErrorLog(110, e.Message);
4455  }
4456 }
4457 
4458 // ---------------------------------------------------------------------------
4459 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4460 {
4461  try
4462  {
4463  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4464  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4466  {
4467  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4468  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4469  if(button == IDNO)
4470  {
4471  Utilities->CallLogPop(1603);
4472  return;
4473  }
4474  }
4475  TimetableChangedFlag = false;
4476  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4477  // added for Beta v0.2b
4478  CreateEditTTTitle = ""; // as above
4479  ConflictPanel->Visible = false;
4480  Level1Mode = BaseMode;
4481  SetLevel1Mode(84);
4482  Utilities->CallLogPop(1606);
4483  }
4484  catch(const Exception &e)
4485  {
4486  ErrorLog(49, e.Message);
4487  }
4488 }
4489 
4490 // ---------------------------------------------------------------------------
4491 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4492 {
4493  try
4494  {
4495  TrainController->LogEvent("LocationNameComboBoxClick");
4496  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4497  if(TTStartTimePtr != 0)
4498  {
4499  LocationNameComboBox->SelectAll();
4500  int SelPos = OneEntryTimetableMemo->SelStart;
4501  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4502  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4503  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4504  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4505  TTEntryChangedFlag = true;
4506  OneEntryTimetableMemo->SetFocus();
4508  SetLevel1Mode(118);
4509  }
4510  Utilities->CallLogPop(1669);
4511  }
4512  catch(const Exception &e)
4513  {
4514  ErrorLog(109, e.Message);
4515  }
4516 }
4517 
4518 // ---------------------------------------------------------------------------
4519 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4520 {
4521  try
4522  {
4523 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4524  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4526  {
4527  Utilities->CallLogPop(1716);
4528  return;
4529  }
4530  TimetableChangedFlag = true;
4531  TTEntryChangedFlag = true;
4532  TimetableValidFlag = false;
4534  SetLevel1Mode(127);
4535  Utilities->CallLogPop(1629);
4536  }
4537  catch(const Exception &e)
4538  {
4539  ErrorLog(66, e.Message);
4540  }
4541 }
4542 
4543 // ---------------------------------------------------------------------------
4544 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4545 {
4546 // forces a recheck for whether addmins/submins buttons should be enabled
4547  try
4548  {
4549  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4550  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4552  SetLevel1Mode(108);
4553  Utilities->CallLogPop(1658);
4554  }
4555  catch(const Exception &e)
4556  {
4557  ErrorLog(106, e.Message);
4558  }
4559 }
4560 
4561 // ---------------------------------------------------------------------------
4562 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4563 {
4564  try
4565  {
4566  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4567  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4568  if(!Track->LocationNameMultiMap.empty())
4569  {
4570  LocationNameComboBox->Text = "Location names";
4571  }
4572  else
4573  {
4574  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4575  }
4576  Utilities->CallLogPop(1677);
4577  }
4578  catch(const Exception &e)
4579  {
4580  ErrorLog(112, e.Message);
4581  }
4582 }
4583 
4584 // ---------------------------------------------------------------------------
4585 
4586 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button,
4587  TShiftState Shift, int X, int Y)
4588 {
4589 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4590  try
4591  {
4592  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4593  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4594  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4595  {
4596  Utilities->CallLogPop(1687);
4597  return;
4598  }
4599  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4600  {
4601  Utilities->CallLogPop(1688);
4602  return;
4603  }
4604  // find item required - 13 pixels per line of text
4605  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4606  // position changing in AllEntriesTTListBox
4607  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4608  {
4610  }
4611  else
4612  {
4613  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4614  }
4615  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4617 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4618  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4619  {
4621  }
4622  else
4623  {
4624  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4625  }
4627  SetLevel1Mode(120);
4628  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4629  Utilities->CallLogPop(1648);
4630  }
4631  catch(const Exception &e)
4632  {
4633  ErrorLog(103, e.Message);
4634  }
4635 }
4636 
4637 // ---------------------------------------------------------------------------
4638 
4639 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4640 {
4641 // Mouseup rather than Mousedown so shows floating label when over train
4642  try
4643  {
4644  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4645  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4646  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4647  {
4648  Utilities->CallLogPop(2087);
4649  return;
4650  }
4652  {
4653  Utilities->CallLogPop(2088);
4654  return;
4655  }
4657  // find item required - 13 pixels per line of text
4658  int TopPos = OAListBox->TopIndex;
4659  int OAIndex;
4660  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
4661  {
4662  Utilities->CallLogPop(2089);
4663  return;
4664  }
4665  else
4666  {
4667  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
4668  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
4669  }
4670  int HPos;
4671  int VPos;
4672  int TrackVectorPosition;
4673  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
4674  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
4675  {
4676  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
4677  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
4678  // as notified by Rokas Serys by email on 16/05/20
4679  {
4680  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
4681  }
4682  else
4683  {
4684  Utilities->CallLogPop(2155); // if not there then ignore
4685  return;
4686  }
4687  }
4688  else // train to enter at a continuation, so value is -TVPos of continuation - 1
4689  {
4690  TrackVectorPosition = -(TrainIDorTVPos + 1);
4691  }
4692  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4693  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4694  // now want to set the offsets to display HPos & VPos in the centre of the screen
4695  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4696  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
4697  int ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4698  int ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4699  if(Display->ZoomOutFlag) // panel displays in either zoom mode
4700  {
4701  Display->ZoomOutFlag = false;
4703  }
4704  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
4705  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
4706  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
4707  Mouse->CursorPos = CursPos;
4708  Utilities->CallLogPop(2090);
4709  }
4710  catch(const Exception &e)
4711  {
4712  ErrorLog(200, e.Message);
4713  }
4714 }
4715 
4716 // ---------------------------------------------------------------------------
4717 
4719 {
4720  enum
4721  {
4722  PreStartTime, ActiveSegment, PostEnd} Segment;
4723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
4724  AllEntriesTTListBox->Clear();
4725  TEVPtr = 0;
4726  TTStartTimePtr = 0;
4727  TTFirstServicePtr = 0;
4728  TTLastServicePtr = 0; // all set to null to begin with
4729  if(TimetableEditVector.empty())
4730  {
4731  TTCurrentEntryPtr = 0;
4732  Utilities->CallLogPop(1681);
4733  return;
4734  }
4735  Segment = PreStartTime;
4736  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4737  {
4738  if(Segment == PreStartTime) // looking for the start time
4739  {
4740  TDateTime TempTime; // dummy
4741  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
4742  {
4743  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
4744  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
4745  Segment = ActiveSegment;
4746  continue;
4747  }
4748  else
4749  {
4750  if(*TEVPtr == "")
4751  {
4752  AllEntriesTTListBox->Items->Add("- Blank");
4753  }
4754  else
4755  {
4756  AnsiString CurrentStr = *TEVPtr;
4757  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4758  {
4759  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
4760  for(int x = 1; x < CurrentStr.Length(); x++)
4761  {
4762  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4763  {
4764  CurrentStr = CurrentStr.SubString(1, (x - 1));
4765  }
4766  }
4767  }
4768  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
4769  }
4770  continue;
4771  }
4772  }
4773  if(Segment == ActiveSegment)
4774  {
4775  if(*TEVPtr != "")
4776  {
4777  if((*TEVPtr)[1] != '*')
4778  {
4780  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
4781  // SaveTTEntryButtonClick - see comment in that function
4782  if(TTFirstServicePtr == 0)
4783  {
4785  }
4787  }
4788  AnsiString Entry = *TEVPtr;
4789  if(Entry[1] == '*')
4790  Entry = "Comment";
4791  else
4792  {
4793  int SCPos = Entry.Pos(';'); // semicolon
4794  int CPos = Entry.Pos(','); // comma
4795  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
4796  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
4797  // description - enter the text up to the comma
4798  // both, semicolon before comma, normal - enter text up to the semicolon
4799  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
4800  // semicolon & no comma - enter text up to the semicolon
4801  if((CPos == 0) && (SCPos == 0))
4802  {
4803  Entry = Entry.SubString(1, 12);
4804  }
4805  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
4806  {
4807  Entry = Entry.SubString(1, CPos - 1);
4808  }
4809  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
4810  {
4811  Entry = Entry.SubString(1, SCPos - 1);
4812  }
4813  else if((CPos > 0) && (SCPos == 0))
4814  {
4815  Entry = Entry.SubString(1, CPos - 1);
4816  }
4817  else
4818  {
4819  Entry = Entry.SubString(1, SCPos - 1);
4820  }
4821  }
4822  AllEntriesTTListBox->Items->Add(Entry);
4823  continue;
4824  }
4825  else
4826  {
4827  Segment = PostEnd;
4828  AllEntriesTTListBox->Items->Add("END (Blank)");
4829  continue;
4830  }
4831  }
4832  if(Segment == PostEnd)
4833  {
4834  if(*TEVPtr == "")
4835  {
4836  AllEntriesTTListBox->Items->Add("+ Blank");
4837  }
4838  else
4839  {
4840  AnsiString CurrentStr = *TEVPtr;
4841  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4842  {
4843  CurrentStr = CurrentStr.SubString(1, 10);
4844  for(int x = 1; x < CurrentStr.Length(); x++)
4845  {
4846  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4847  {
4848  CurrentStr = CurrentStr.SubString(1, (x - 1));
4849  }
4850  }
4851  }
4852  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
4853  }
4854  continue;
4855  }
4856  }
4857  if(TTStartTimePtr == 0)
4858  {
4859  TTStartTimeBox->Text = "";
4860  }
4861  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
4862  Utilities->CallLogPop(1680);
4863 }
4864 // ---------------------------------------------------------------------------
4865 
4866 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
4867 {
4868  try
4869  {
4870  if(TimetableEditVector.empty())
4871  {
4872  return; // should be able to access this if it is but keep in for safety
4873  }
4874  TrainController->LogEvent("AZOrderClick");
4875  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
4876  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
4877  {
4878  TTEVPtr SortStart, SortEnd;
4879  UnicodeString MessageStr =
4880  "If you wish to preserve the original order don't make any changes whilst in alphabetical order.\n\nIn that case use alphabetical order to find the service required, click it to display it, then revert to the original order where the same service will be displayed and can be changed.";
4881  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
4884  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
4885  if(TTFirstServicePtr != NULL)
4886  {
4887  SortStart = TTFirstServicePtr;
4888  }
4889  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
4890  if(TTLastServicePtr != NULL)
4891  {
4892  SortEnd = TTLastServicePtr + 1;
4893  }
4894  std::sort(SortStart, SortEnd);
4896  bool CurrentEntryChanged = false;
4897  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
4898  {
4899  if(TTSelectedEntry == *x)
4900  {
4901  TTCurrentEntryPtr = x;
4902  CurrentEntryChanged = true;
4903  }
4904  }
4905  if(!CurrentEntryChanged)
4906  {
4908  }
4909  AZOrderButton->Caption = AnsiString("Original Order");
4910  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
4911  }
4912  else
4913  {
4915  {
4916  UnicodeString MessageStr =
4917  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
4918  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
4919  if(button == IDNO)
4920  {
4921  TimetableChangedFlag = true;
4922  TimetableValidFlag = false;
4924  SetLevel1Mode(135);
4925  Utilities->CallLogPop(2166);
4926  return;
4927  }
4928  }
4932  bool CurrentEntryChanged = false;
4933  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
4934  {
4935  if(TTSelectedEntry == *x)
4936  {
4937  TTCurrentEntryPtr = x;
4938  CurrentEntryChanged = true;
4939  }
4940  }
4941  if(!CurrentEntryChanged)
4942  {
4944  }
4945  AZOrderButton->Caption = AnsiString("A-Z Order");
4946  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
4947  }
4948  TimetableChangedFlag = true;
4949  TimetableValidFlag = false;
4952  SetLevel1Mode(136);
4953  Utilities->CallLogPop(2165);
4954  }
4955  catch(const Exception &e)
4956  {
4957  ErrorLog(211, e.Message);
4958  }
4959 }
4960 
4961 // ---------------------------------------------------------------------------
4962 
4963 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
4964 {
4965  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
4966  AnsiString OutStr = "";
4967  int x = 1; // AnsiString arrays start at 1
4968 
4969  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
4970  {
4971  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
4972  {
4973  OutStr += ',';
4974  x++;
4975  x++;
4976  }
4977  else
4978  {
4979  OutStr += ConvStr[x];
4980  x++;
4981  }
4982  }
4983  if(x == ConvStr.Length())
4984  OutStr += ConvStr[x]; // add the last character
4985 
4986 // strip any excess commas from the end
4987  if(OutStr != "")
4988  {
4989  while(OutStr[OutStr.Length()] == ',')
4990  {
4991  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
4992  if(OutStr == "")
4993  break; // if consisted of just commas then without this would fail on range error when becomes a null string
4994  }
4995  }
4996  ConvStr = OutStr;
4997  if(ConvStr == "")
4998  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
4999  // when AllCommas will be true
5000  Utilities->CallLogPop(1846);
5001 }
5002 
5003 // ---------------------------------------------------------------------------
5004 
5006 {
5007 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5008  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5009  entries
5010 */
5011  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5012  PreviousTTEntryButton->Enabled = false;
5013  NextTTEntryButton->Enabled = false;
5014  AddMinsButton->Enabled = false;
5015  SubMinsButton->Enabled = false;
5016  CopyTTEntryButton->Enabled = false;
5017  CutTTEntryButton->Enabled = false;
5018  PasteTTEntryButton->Enabled = false;
5019  DeleteTTEntryButton->Enabled = false;
5020  SaveTTEntryButton->Enabled = false;
5021  SaveTTButton->Enabled = false;
5022  SaveTTAsButton->Enabled = false;
5023  ValidateTimetableButton->Enabled = false;
5024  AZOrderButton->Enabled = false;
5025  TTServiceSyntaxCheckButton->Enabled = false;
5026  NewTTEntryButton->Enabled = false;
5027  MoveTTEntryUpButton->Enabled = false;
5028  MoveTTEntryDownButton->Enabled = false;
5029  CancelTTEntryButton->Enabled = false;
5030  RestoreTTButton->Enabled = false;
5031  ExportTTButton->Enabled = false;
5032  ConflictAnalysisButton->Enabled = false;
5033  ExitTTModeButton->Enabled = true;
5034 
5036  {
5037  AZOrderButton->Enabled = true;
5038  }
5039 
5041  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5042 
5043  if(CreateEditTTFileName == "")
5044  {
5045  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5046  }
5047  else
5048  {
5049  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5050  }
5051 
5052  if(TTStartTimePtr != 0) // Null means start time not yet set
5053  {
5054  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5055  }
5056 // start time now set & displayed
5057 
5059  {
5060  InfoPanel->Visible = true;
5061  InfoPanel->Caption = "Select option or change entry";
5062  if(RailwayTitle != "")
5063  {
5064  ShowHideTTButton->Enabled = true;
5065  }
5066  else
5067  {
5068  ShowHideTTButton->Enabled = false;
5069  }
5070  ExitTTModeButton->Enabled = true;
5071  AllEntriesTTListBox->Enabled = true;
5072  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5073  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5074  {
5075  bool ValidFlag = true;
5076  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5077  {
5078  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5079  {
5080  ValidFlag = false;
5081  break;
5082  }
5083  }
5084  if(ValidFlag)
5085  {
5086  if(AnsiAddSubText.ToInt() != 0)
5087  {
5088  AddMinsButton->Enabled = true;
5089  SubMinsButton->Enabled = true;
5090  }
5091  }
5092  }
5094  {
5095  RestoreTTButton->Enabled = true;
5096  }
5098  { // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5099  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5100  ValidateTimetableButton->Enabled = true;
5101  }
5103  {
5104  ExportTTButton->Enabled = true;
5105  ConflictAnalysisButton->Enabled = true;
5106  }
5107  if(TTCurrentEntryPtr != 0)
5108  {
5109  CopyTTEntryButton->Enabled = true;
5110  CutTTEntryButton->Enabled = true;
5111  DeleteTTEntryButton->Enabled = true;
5112  }
5113  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5114  {
5115  SaveTTButton->Enabled = true;
5116  }
5117  if(!TimetableEditVector.empty())
5118  {
5119  SaveTTAsButton->Enabled = true;
5120  }
5122  {
5123  NewTTEntryButton->Enabled = true;
5124  }
5125  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5126  {
5127  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5128  {
5129  NextTTEntryButton->Enabled = true;
5130  MoveTTEntryDownButton->Enabled = true;
5131  }
5133  {
5134  PreviousTTEntryButton->Enabled = true;
5135  MoveTTEntryUpButton->Enabled = true;
5136  }
5137  }
5138  if(TTCurrentEntryPtr > 0)
5139  {
5140  if(*TTCurrentEntryPtr != "")
5141  {
5143  {
5144  TTServiceSyntaxCheckButton->Enabled = true;
5145  }
5146  }
5147  }
5148  if(CopiedEntryFlag)
5149  {
5150  PasteTTEntryButton->Enabled = true;
5151  }
5152  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5153  if(TTCurrentEntryPtr > 0)
5154  {
5155 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5157  {
5158  bool ServiceEntry = true;
5159  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5160  }
5161  else
5162  {
5163  bool ServiceEntry = false;
5164  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5165  }
5166  }
5167  }
5168  else
5169  {
5170  CancelTTEntryButton->Enabled = true;
5171  SaveTTEntryButton->Enabled = true;
5172  ShowHideTTButton->Enabled = false;
5173  ExitTTModeButton->Enabled = false;
5174  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5175  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5176  InfoPanel->Visible = true;
5177  }
5178  Utilities->CallLogPop(1600);
5179 }
5180 
5181 // ---------------------------------------------------------------------------
5182 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5183 {
5184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5185  AnsiString((short)ServiceEntry));
5186  OneEntryTimetableMemo->Clear();
5187  if(ServiceEntry)
5188  {
5189  TrainController->StripSpaces(1, Data);
5190  while(true)
5191  {
5192  int CommaPos = Data.Pos(',');
5193  if((CommaPos == 0) && (Data != ""))
5194  {
5195  CommaPos = Data.Length() + 1;
5196  }
5197  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5198  if(Data.Length() <= CommaPos)
5199  break;
5200  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5201  }
5202  }
5203  else
5204  {
5205  OneEntryTimetableMemo->Text = Data;
5206  }
5207  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5208 
5209  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5210  {
5211  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5212  TotalLines--;
5213  if(TotalLines < 1)
5214  break;
5215  }
5216  OneEntryTimetableMemo->HideSelection = true;
5217  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5218  OneEntryTimetableMemo->SelLength = 0;
5220  Utilities->CallLogPop(1602);
5221 }
5222 // ---------------------------------------------------------------------------
5223 
5225 {
5226  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5227  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5228  {
5229  HighlightPanel->Top = 32;
5230  HighlightPanel->Caption = "";
5231  HighlightPanel->Width = 100;
5232  HighlightPanel->Visible = false;
5233  }
5234  else
5235  {
5236  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5237  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5238  {
5239  for(int x = 1; x < CurrentStr.Length(); x++)
5240  {
5241  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5242  {
5243  CurrentStr = CurrentStr.SubString(1, (x - 1));
5244  }
5245  }
5246  }
5247  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5248  if(HighlightPanel->Top < 32)
5249  HighlightPanel->Visible = false;
5250  else
5251  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5252  HighlightPanel->Caption = CurrentStr;
5253  if(AllEntriesTTListBox->Items->Count > 46) //because the scrollbar will be present
5254  HighlightPanel->Width = 82;
5255  else
5256  HighlightPanel->Width = 100;
5257  }
5258  Utilities->CallLogPop(1709);
5259 }
5260 
5261 // ---------------------------------------------------------------------------
5263 {
5264  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5265  {
5266  return false;
5267  }
5268  TDateTime DummyTime;
5269  bool TimesPresent = false;
5270 
5271  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5272  {
5273  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5274  {
5275  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5276  {
5277  TimesPresent = true;
5278  break;
5279  }
5280  }
5281  if(TimesPresent)
5282  break;
5283  }
5284  return TimesPresent;
5285 }
5286 
5287 // ---------------------------------------------------------------------------
5288 // end of Timetable editing functions
5289 // ---------------------------------------------------------------------------
5290 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5291 {
5292  try
5293  {
5294  TrainController->LogEvent("ExitMenuItemClick");
5295  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5297  {
5298  UnicodeString MessageStr =
5299  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5300  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5301  if(button == IDNO)
5302  {
5303  Utilities->CallLogPop(1711);
5304  return;
5305  }
5306  }
5307  if(FileChangedFlag)
5308  {
5309  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5310  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5311  if(button == IDNO)
5312  {
5313  Utilities->CallLogPop(1180);
5314  return;
5315  }
5316  }
5317  if((TempTTFileName != "") && FileExists(TempTTFileName))
5318  {
5319  DeleteFile(TempTTFileName);
5320  }
5321  Utilities->CallLogPop(1181);
5322  Application->Terminate();
5323  }
5324  catch(const Exception &e)
5325  {
5326  ErrorLog(140, e.Message);
5327  }
5328 }
5329 // ---------------------------------------------------------------------------
5330 
5331 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5332 {
5333  try
5334  {
5335  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5336  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5337  if(TrackInfoOnOffMenuItem->Caption == "Show")
5338  {
5339  TrackInfoOnOffMenuItem->Caption = "Hide";
5340  }
5341  else
5342  {
5343  TrackInfoOnOffMenuItem->Caption = "Show";
5344  }
5345  Utilities->CallLogPop(1183);
5346  }
5347  catch(const Exception &e)
5348  {
5349  ErrorLog(173, e.Message);
5350  }
5351 }
5352 // ---------------------------------------------------------------------------
5353 
5354 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5355 {
5356  try
5357  {
5358  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5359  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5360  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5361  {
5362  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5363  }
5364  else
5365  {
5366  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5367  }
5368  Utilities->CallLogPop(1184);
5369  }
5370  catch(const Exception &e)
5371  {
5372  ErrorLog(141, e.Message);
5373  }
5374 }
5375 
5376 // ---------------------------------------------------------------------------
5377 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5378 {
5379  try
5380  {
5381  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5382  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5383  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5384  {
5385  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5386  }
5387  else
5388  {
5389  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5390  }
5391  Utilities->CallLogPop(1185);
5392  }
5393  catch(const Exception &e)
5394  {
5395  ErrorLog(142, e.Message);
5396  }
5397 }
5398 
5399 // ---------------------------------------------------------------------------
5400 // Dragging Functions
5401 // ---------------------------------------------------------------------------
5402 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5403 {
5404 // allow in zoom out mode
5405  try
5406  {
5407 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5408  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5409  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5410  {
5411  Accept = true;
5412  int PPLeft = PerformancePanel->Left;
5413  int PPTop = PerformancePanel->Left;
5414 
5415  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5416  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5417  if((PPLeft + PerformancePanel->Width) < 32)
5418  PPLeft = 32 - PerformancePanel->Width;
5419  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5420  PPLeft = MainScreen->Left + MainScreen->Width;
5421  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5422  PPTop = MainScreen->Top - PerformancePanel->Height;
5423  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5424  PPTop = MainScreen->Top + MainScreen->Height - 20;
5425  PerformancePanel->Left = PPLeft;
5426  PerformancePanel->Top = PPTop;
5427  }
5428  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5429  // not the listbox because that used for selecting trains
5430  {
5431  Accept = true;
5432  int OALeft = OperatorActionPanel->Left;
5433  int OATop = OperatorActionPanel->Left;
5434 
5435  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5436  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5437  if((OALeft + OperatorActionPanel->Width) < 32)
5438  OALeft = 32 - OperatorActionPanel->Width;
5439  if(OALeft > (MainScreen->Left + MainScreen->Width))
5440  OALeft = MainScreen->Left + MainScreen->Width;
5441  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5442  OATop = MainScreen->Top - OperatorActionPanel->Height;
5443  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5444  OATop = MainScreen->Top + MainScreen->Height - 20;
5445  OperatorActionPanel->Left = OALeft;
5446  OperatorActionPanel->Top = OATop;
5447  }
5448  else
5449  Accept = false;
5450  Utilities->CallLogPop(1186);
5451  }
5452  catch(const Exception &e)
5453  {
5454  ErrorLog(143, e.Message);
5455  }
5456 }
5457 
5458 // ---------------------------------------------------------------------------
5459 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5460 {
5461 // allow in zoom out mode
5462  try
5463  {
5464  TrainController->LogEvent("PerformancePanelStartDrag");
5465  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5466  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5467  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5468  Utilities->CallLogPop(1187);
5469  }
5470  catch(const Exception &e)
5471  {
5472  ErrorLog(144, e.Message);
5473  }
5474 }
5475 // ---------------------------------------------------------------------------
5476 
5477 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5478 
5479 {
5480 // allow in zoom out mode
5481  try
5482  {
5483  TrainController->LogEvent("OperatorActionPanelStartDrag");
5484  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5485  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5486  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5487  Utilities->CallLogPop(2091);
5488  }
5489  catch(const Exception &e)
5490  {
5491  ErrorLog(201, e.Message);
5492  }
5493 }
5494 
5495 // ---------------------------------------------------------------------------
5496 // Mouse Functions
5497 // ---------------------------------------------------------------------------
5498 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5499  // caller function - stops master clock
5500 {
5501 // have to allow in zoom out mode
5502  try
5503  {
5504  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5505  bool ClockState = Utilities->Clock2Stopped;
5506  Utilities->Clock2Stopped = true;
5507 
5508  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5509  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5510  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5511  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5512  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5513 
5515  {
5516  if(!Display->ZoomOutFlag)
5517  MainScreenMouseDown2(0, Button, Shift, X, Y);
5518  else
5519  MainScreenMouseDown3(0, Button, Shift, X, Y);
5520  }
5521  Utilities->Clock2Stopped = ClockState;
5522  Utilities->CallLogPop(33);
5523  }
5524  catch(const Exception &e)
5525  {
5526  ErrorLog(19, e.Message);
5527  }
5528 }
5529 
5530 // ---------------------------------------------------------------------------
5531 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5532 {
5533  try
5534  {
5535  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5536  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5537  "," + AnsiString(Y));
5538  // unplot GapFlash graphics if plotted & cancel gap flashing (either key down)
5539  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5541  {
5544  Track->GapFlashFlag = false;
5545  }
5546  int HLoc, VLoc;
5547  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5548  int NoOffsetX, NoOffsetY;
5549  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5550  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5551  {
5552  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5553  int Dummy; // unused in next function
5554  AnsiString Text = ""; //needed for TextFound but not used
5555  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X, Y, Dummy) &&
5556  !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
5557  {
5560  WholeRailwayMoving = true;
5561  Screen->Cursor = TCursor(-22); // Four arrows;
5562  }
5563 
5564  else if(Level2TrackMode == AddText)
5565  {
5566  TrainController->LogEvent("mbRight + AddText");
5568  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
5569  {
5570  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
5571  {
5573  if(NoRailway())
5574  {
5575  EditMenu->Enabled = false;
5576  }
5577  else
5578  EditMenu->Enabled = true;
5579  }
5580  }
5581  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
5582  Utilities->CallLogPop(34);
5583  return;
5584  }
5585  else if(Level2TrackMode == AddGraphic)
5586  {
5587  TrainController->LogEvent("mbRight + AddGraphic");
5588  if(Track->UserGraphicVector.empty()) // no user graphics
5589  {
5590  Utilities->CallLogPop(2180);
5591  return;
5592  }
5593  int UGIVecPos;
5594  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
5595  {
5596  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
5598  if(NoRailway())
5599  {
5600  EditMenu->Enabled = false;
5601  }
5602  else
5603  EditMenu->Enabled = true;
5604  }
5605  Utilities->CallLogPop(2181);
5606  return;
5607  }
5608 
5609  else if(Level2TrackMode == AddTrack)
5610  {
5611  TrainController->LogEvent("mbRight + AddTrack");
5612  bool TrackEraseSuccessfulFlag;
5613  int ErasedTrackVectorPosition;
5614  Screen->Cursor = TCursor(-11); // Hourglass;
5615  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
5616  if(TrackEraseSuccessfulFlag)
5617  {
5618  if(ErasedTrackVectorPosition > -1)
5619  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
5622  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
5623  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
5624  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
5625  if(Track->GapsUnset(1))
5626  {
5627  SetGapsButton->Enabled = true;
5628  }
5629  // only enable if there are gaps still to be set (returns false for no track)
5630  else
5631  {
5632  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
5633  {
5634  TrackOKButton->Enabled = true;
5635  }
5636  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
5637  }
5638  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
5639  {
5640  SetLengthsButton->Enabled = false;
5641  }
5642  if(NoRailway())
5643  {
5644  EditMenu->Enabled = false;
5645  }
5646  else
5647  EditMenu->Enabled = true;
5648  }
5649  Screen->Cursor = TCursor(-2); // Arrow
5650  Utilities->CallLogPop(35);
5651  return;
5652  }
5653  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
5654  {
5655  TrainController->LogEvent("mbRight + DistanceContinuing");
5657  bool LeadingPointsAtLastElement = false;
5658  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
5659  {
5660  if(ConstructPrefDir->PrefDirSize() == 0)
5661  {
5663  SetLevel1Mode(64);
5665  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
5666  Utilities->CallLogPop(1526);
5667  return;
5668  }
5671  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
5672  if(!LeadingPointsAtLastElement)
5673  {
5674  TrackLengthPanel->Visible = true;
5675  TrackLengthPanel->SetFocus();
5676  InfoPanel->Visible = true;
5677  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
5678  RestoreAllDefaultLengthsButton->Enabled = true;
5679  ResetDefaultLengthButton->Enabled = true;
5680  LengthOKButton->Enabled = true;
5681  DistanceBox->Text = AnsiString(OverallDistance);
5682  if(OverallSpeedLimit > -1)
5683  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
5684  else
5685  SpeedLimitBox->Text = "Mixed";
5686  }
5687  else
5688  {
5689  TrackLengthPanel->Visible = true;
5690  TrackLengthPanel->SetFocus();
5691  InfoPanel->Visible = true;
5692  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
5693  RestoreAllDefaultLengthsButton->Enabled = false;
5694  ResetDefaultLengthButton->Enabled = false;
5695  LengthOKButton->Enabled = false;
5696  }
5698  }
5699  Utilities->CallLogPop(36);
5700  return;
5701  }
5702 
5703  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
5704  {
5705  TrainController->LogEvent("mbRight + PrefDirContinuing");
5707 // RlyFile = false; - don't alter this just for PrefDir changes
5708  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
5709  {
5710  if(ConstructPrefDir->PrefDirSize() == 0)
5711  {
5713  SetLevel1Mode(14); // all PrefDir truncated
5714  Utilities->CallLogPop(37);
5715  return;
5716  }
5718  }
5720  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
5721  Utilities->CallLogPop(38);
5722  return;
5723  }
5724 
5725  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
5726  {
5727  TrainController->LogEvent("mbRight + != PrefDirContinuing");
5729 // RlyFile = false; - don't alter this just for PrefDir changes
5732  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
5733  Utilities->CallLogPop(39);
5734  return;
5735  }
5736 
5737  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
5738  {
5739  TrainController->LogEvent("mbRight + OperMode");
5740  bool FoundFlag;
5741  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
5742  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
5743  {
5745  // signaller control of train
5746  if(SelectedTrainID > -1)
5747  {
5750  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
5751  {
5752  if(Train.TrainMode == Signaller)
5753  {
5755  }
5756  }
5757  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
5759  !Train.StepForwardFlag))
5760  // don't allow signaller popup menu in timetable mode unless stopped,
5761  // or when coming to a stop or leaving at a continuation when under signaller control
5762  // or when failed
5763  {
5764  // don't allow selection if another stopped train at a bridge position
5765  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
5766  {
5767  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
5768  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
5769  if((TrainID01 > -1) && (TrainID23 > -1))
5770  {
5771  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
5772  Utilities->CallLogPop(1103);
5773  return;
5774  }
5775  }
5776  if(Train.TrainMode == Timetable)
5777  {
5778  TakeSignallerControlMenuItem->Enabled = true;
5779  TimetableControlMenuItem->Enabled = false;
5780  ChangeDirectionMenuItem->Enabled = false;
5781  MoveForwardsMenuItem->Enabled = false;
5782  SignallerJoinedByMenuItem->Enabled = false;
5783  RepairFailedTrainMenuItem->Enabled = false;
5784  StepForwardMenuItem->Enabled = false;
5785  RemoveTrainMenuItem->Enabled = false;
5786  PassRedSignalMenuItem->Enabled = false;
5787  SignallerControlStopMenuItem->Enabled = false;
5788  }
5789  else // signaller mode
5790  {
5791  TakeSignallerControlMenuItem->Enabled = false;
5792  if((Train.Crashed) || (Train.Derailed))
5793  {
5794  TimetableControlMenuItem->Enabled = false;
5795  ChangeDirectionMenuItem->Enabled = false;
5796  MoveForwardsMenuItem->Enabled = false;
5797  SignallerJoinedByMenuItem->Enabled = false;
5798  RepairFailedTrainMenuItem->Enabled = false;
5799  StepForwardMenuItem->Enabled = false;
5800  PassRedSignalMenuItem->Enabled = false;
5801  SignallerControlStopMenuItem->Enabled = false;
5802  RemoveTrainMenuItem->Enabled = true;
5803  }
5804  else if(Train.Stopped())
5805  {
5806  if(Train.TimetableFinished)
5807  {
5808  TimetableControlMenuItem->Enabled = false;
5809  }
5810  else
5811  {
5812  if(Train.RestoreTimetableLocation == "") // en route
5813  {
5814  TimetableControlMenuItem->Enabled = true;
5815  }
5816  else
5817  {
5818  // obtain train location & check if OK for restoration of tt control
5819  AnsiString LocName = "";
5820  if(Train.LeadElement > -1)
5821  {
5822  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
5823  }
5824  if((LocName == "") && (Train.MidElement > -1))
5825  {
5826  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
5827  }
5828  if(Train.RestoreTimetableLocation == LocName)
5829  {
5830  TimetableControlMenuItem->Enabled = true;
5831  }
5832  else
5833  {
5834  TimetableControlMenuItem->Enabled = false;
5835  }
5836  }
5837  }
5838 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
5839  ChangeDirectionMenuItem->Enabled = true;
5840  if(Train.LeadElement > -1)
5841  {
5843  {
5844  ChangeDirectionMenuItem->Enabled = false;
5845  }
5846  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
5847  {
5848  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
5849  .TrackType == Continuation)
5850  {
5851  ChangeDirectionMenuItem->Enabled = false;
5852  }
5853  }
5854  }
5855  else
5856  ChangeDirectionMenuItem->Enabled = false;
5857  if(Train.MidElement > -1)
5858  {
5860  {
5861  ChangeDirectionMenuItem->Enabled = false;
5862  }
5863  }
5864  else
5865  ChangeDirectionMenuItem->Enabled = false;
5866  if(Train.LagElement > -1)
5867  {
5869  {
5870  ChangeDirectionMenuItem->Enabled = false;
5871  }
5872  }
5873  RemoveTrainMenuItem->Enabled = true;
5874  SignallerControlStopMenuItem->Enabled = false;
5875  SignallerJoinedByMenuItem->Enabled = false;
5876  RepairFailedTrainMenuItem->Enabled = false;
5877  StepForwardMenuItem->Enabled = false;
5878  MoveForwardsMenuItem->Enabled = false;
5879  PassRedSignalMenuItem->Enabled = false;
5880  if(Train.AbleToMove(0))
5881  {
5882  MoveForwardsMenuItem->Enabled = true;
5884  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
5885  } // fails on trying to calc AutoSig time delay for resetting signals
5886  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
5887  {
5888  PassRedSignalMenuItem->Enabled = true;
5889  StepForwardMenuItem->Enabled = true;
5890  }
5891  TTrain *AdjacentTrain;
5892  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
5893  {
5894  SignallerJoinedByMenuItem->Enabled = true;
5895  }
5896  if(Train.TrainFailed)
5897  {
5898  RepairFailedTrainMenuItem->Enabled = true;
5899  }
5900  }
5901  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
5902  // mid move, & SetTrainMovementValues only intended to be called when stopped
5903  {
5904  TimetableControlMenuItem->Enabled = false;
5905  ChangeDirectionMenuItem->Enabled = false;
5906  RemoveTrainMenuItem->Enabled = false;
5907  MoveForwardsMenuItem->Enabled = false;
5908  SignallerJoinedByMenuItem->Enabled = false;
5909  RepairFailedTrainMenuItem->Enabled = false;
5910  PassRedSignalMenuItem->Enabled = false;
5911  StepForwardMenuItem->Enabled = false;
5912  SignallerControlStopMenuItem->Enabled = true;
5913  }
5914  }
5915  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
5916  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
5918  PopupMenu->Popup(X, Y); // menu stops everything so reset timetable time when restarts
5919  TrainController->BaseTime = TDateTime::CurrentDateTime();
5921  Utilities->CallLogPop(40);
5922  return;
5923  }
5924  }
5925  }
5926 
5927  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
5928  {
5929  TrainController->LogEvent("mbRight + RouteContinuing");
5931  Utilities->CallLogPop(41);
5932  return;
5933  }
5934 
5935  else if(RouteCancelFlag) // allow in PreStart
5936  {
5937  TrainController->LogEvent("mbRight + RouteCancelFlag");
5938  Screen->Cursor = TCursor(-11); // Hourglass;
5939  // stop clock as sometimes takes several seconds
5940  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
5942  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
5943  {
5944  ClearandRebuildRailway(6); // to replot new shorter route
5945  }
5947  TrainController->BaseTime = TDateTime::CurrentDateTime();
5949  Screen->Cursor = TCursor(-2); // Arrow
5950  }
5951 
5952  else // gap flashing, don't allow to interfere with RouteCancelFlag
5953  {
5954  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
5955  int Position;
5956  TTrackElement TrackElement;
5957  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement));
5958  {
5959  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
5960  {
5961  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
5962  { // don't flash if train on either gap element
5963  Track->GapFlashGreenPosition = TrackElement.Conn[0];
5968  Track->GapFlashRedPosition = Position;
5973  Track->GapFlashFlag = true;
5974  }
5975  }
5976  }
5977  Utilities->CallLogPop(42);
5978  return; // covers above else & included here in case any more usermodes added later
5979  }
5980  }
5981 
5982  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
5983  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
5984  int Position;
5985  TTrackElement TrackElement;
5986  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement));
5987  {
5988  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
5989  {
5990  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
5991  { // don't flash if train on either gap element
5992  Track->GapFlashGreenPosition = TrackElement.Conn[0];
5996  Track->GapFlashRedPosition = Position;
6000  Track->GapFlashFlag = true;
6001  }
6002  }
6003  }
6004  Utilities->CallLogPop(67);
6005  return; // covers above else & included here in case any more usermodes added later
6006  }
6007 
6008 // Left Mouse Button Functions
6009  if(RouteCancelFlag)
6011  mbLeftDown = true;
6012 
6013  if(Level2TrackMode == AddTrack)
6014  {
6015  TrainController->LogEvent("mbLeft + AddTrack");
6016  Screen->Cursor = TCursor(-11); // Hourglass;
6018  bool TrackLinkingRequiredFlag;
6019  int CurrentTag;
6020  TSpeedButton *TempSpeedButton = 0;
6021  if(CurrentSpeedButton)
6022  {
6023  CurrentTag = CurrentSpeedButton->Tag;
6024  TempSpeedButton = CurrentSpeedButton;
6025  }
6026  else
6027  CurrentTag = 0;
6028  bool InternalChecks = true;
6029  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6030  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6031  EditMenu->Enabled = true;
6032  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6033  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6034  if(TrackLinkingRequiredFlag)
6035  {
6036  Track->SetTrackFinished(false);
6037  }
6038  SetTrackBuildImages(10);
6039  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6040  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6041  if(Track->GapsUnset(2))
6042  {
6043  SetGapsButton->Enabled = true;
6044  }
6045  // only enable if there are gaps still to be set (returns false for no track)
6046  else
6047  {
6048  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6049  {
6050  TrackOKButton->Enabled = true;
6051  }
6052  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6053  }
6054  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6055  {
6056  SetLengthsButton->Enabled = false;
6057  }
6058  if(TempSpeedButton) // restore button if was pressed
6059  {
6060  CurrentSpeedButton = TempSpeedButton;
6061  CurrentSpeedButton->Down = true;
6062  }
6063  Screen->Cursor = TCursor(-2); // Arrow
6064  Utilities->CallLogPop(44);
6065  return;
6066  }
6067 
6068  else if(Level2TrackMode == AddGraphic)
6069  {
6070  TrainController->LogEvent("mbLeft + AddGraphic");
6071  ResetChangedFileDataAndCaption(24, false);
6072  TUserGraphicItem NewGI;
6073  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6074  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6075  {
6076  NewGI.UserGraphic = UGMIt->second;
6077  NewGI.Width = UGMIt->second->Width;
6078  NewGI.Height = UGMIt->second->Height;
6080  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6081  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6082  Track->UserGraphicVector.push_back(NewGI);
6083  Display->PlotAndAddUserGraphic(1, NewGI);
6084  }
6085  else
6086  {
6087  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6088  Utilities->CallLogPop(2195);
6089  return;
6090  }
6091  MoveTextOrGraphicButton->Enabled = true;
6092  EditMenu->Enabled = true;
6093  Utilities->CallLogPop(2182);
6094  return;
6095  }
6096 
6097  else if(Level2TrackMode == AddLocationName)
6098  {
6099  TrainController->LogEvent("mbLeft + AddLocationName");
6101  bool FoundFlag;
6102  TTrackElement TrackElement;
6103  AnsiString NameString;
6104  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6105  if(!FoundFlag)
6106  {
6107  Utilities->CallLogPop(45);
6108  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6109  }
6110  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6111  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6112  TTrackElement& ValidElement = InactiveTrackElement1;
6113  unsigned int ValidPosition;
6114  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6115  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6116  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6117  {
6118  Utilities->CallLogPop(46);
6119  return; // element not valid
6120  }
6121  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6122  (InactiveTrackElement1.TrackType == Concourse))
6123  {
6124  ValidElement = InactiveTrackElement1;
6125  ValidPosition = InactivePair.first;
6126  }
6127  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6128  (InactiveTrackElement2.TrackType == Concourse))
6129  {
6130  ValidElement = InactiveTrackElement2;
6131  ValidPosition = InactivePair.second;
6132  }
6133  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6134 
6135  // put a square box round element to show selection
6136  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6137  LocationNameTextBox->Visible = true;
6138  LocationNameTextBox->SetFocus();
6139  NameString = Track->GetLocationName(ValidPosition);
6140  LocationNameTextBox->Text = NameString;
6141  InfoPanel->Visible = true;
6142  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6143 
6144  Track->LNPendingList.clear();
6145  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6146  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6147  Utilities->CallLogPop(47);
6148  return;
6149  }
6150 
6151  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6152  // prior to selecting start element
6153  {
6154  TrainController->LogEvent("mbLeft + DistanceStart");
6156  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6157  {
6160  SetLevel1Mode(65);
6162  SetLevel2TrackMode(30);
6163  }
6164  Utilities->CallLogPop(48);
6165  return;
6166  }
6167 
6168  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6169  // prior to selecting finish element
6170  {
6171  TrainController->LogEvent("mbLeft + DistanceContinuing");
6173  bool FinishElement = false, LeadingPointsAtLastElement = false;
6174  Screen->Cursor = TCursor(-11); // Hourglass;
6175  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6176  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6177  { // not same as start element
6178  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6179  {
6182  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6183  if(FinishElement)
6184  {
6185  TrackLengthPanel->Visible = true;
6186  TrackLengthPanel->SetFocus();
6187  InfoPanel->Visible = true;
6188  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6189  RestoreAllDefaultLengthsButton->Enabled = true;
6190  ResetDefaultLengthButton->Enabled = true;
6191  LengthOKButton->Enabled = true;
6192  DistanceBox->Text = AnsiString(OverallDistance);
6193  if(OverallSpeedLimit > -1)
6194  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6195  else
6196  SpeedLimitBox->Text = "Mixed";
6198  Screen->Cursor = TCursor(-2); // Arrow
6199  Utilities->CallLogPop(1527);
6200  return;
6201  }
6202  else
6203  {
6204  if(!LeadingPointsAtLastElement)
6205  {
6206  TrackLengthPanel->Visible = true;
6207  TrackLengthPanel->SetFocus();
6208  InfoPanel->Visible = true;
6209  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6210  RestoreAllDefaultLengthsButton->Enabled = true;
6211  ResetDefaultLengthButton->Enabled = true;
6212  LengthOKButton->Enabled = true;
6213  DistanceBox->Text = AnsiString(OverallDistance);
6214  if(OverallSpeedLimit > -1)
6215  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6216  else
6217  SpeedLimitBox->Text = "Mixed";
6218  // Level2TrackMode = DistanceContinuing;
6219  // SetLevel2TrackMode();
6220  }
6221  else
6222  {
6223  TrackLengthPanel->Visible = true;
6224  TrackLengthPanel->SetFocus();
6225  InfoPanel->Visible = true;
6226  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6227  RestoreAllDefaultLengthsButton->Enabled = false;
6228  ResetDefaultLengthButton->Enabled = false;
6229  LengthOKButton->Enabled = false;
6230  // Level2TrackMode = DistanceContinuing;
6231  // SetLevel2TrackMode();
6232  }
6233  }
6234  }
6235  }
6236  else // same as start element
6237  {
6240  SetLevel2TrackMode(54);
6241  Screen->Cursor = TCursor(-2); // Arrow
6242  Utilities->CallLogPop(1713);
6243  return;
6244  }
6246  Screen->Cursor = TCursor(-2); // Arrow
6247  Utilities->CallLogPop(1490);
6248  return;
6249  }
6250 
6251  else if(Level2TrackMode == GapSetting)
6252  {
6253  TrainController->LogEvent("mbLeft + GapSetting");
6255  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6256  // & it is highlighted
6257  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6258  {
6259  Utilities->CallLogPop(50);
6260  return; // true if finds one
6261  }
6262  InfoPanel->Visible = true;
6263  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6264  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6265  Delay(0, 500); // 500 msec delay before next selection requested
6266 
6267  // ClearandRebuildRailway(8);//get rid of gap selections
6268  // need to call this later when new gap displayed, else old gap remains
6269 
6270  // now back to highlighting next gap
6271  // bool LocError = false;
6272  if(!(HighLightOneGap(1, HLoc, VLoc)))
6273  {
6274  // all gaps set
6275  ShowMessage("All gaps set");
6276  if(Level2TrackMode == AddTrack)
6277  {
6279  SetLevel1Mode(66);
6280  SetLevel2TrackMode(31);
6281  }
6282  else
6283  {
6285  SetLevel1Mode(37);
6286  }
6287  ClearandRebuildRailway(9); // get rid of last gap ellipse
6288  Utilities->CallLogPop(51);
6289  return;
6290  }
6291  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6292  // by another call to MainScreenMouseDown
6293  }
6294 
6295  else if(Level2TrackMode == AddText)
6296  {
6297  TrainController->LogEvent("mbLeft + AddText");
6299  // X & Y are relative to Display output, but TextBox is placed relative to Form
6300  // if mouse position on first character of an existing piece of text reload it into the editor
6301 
6302  bool TextFoundFlag = false;
6303  int TrueX = 0, TrueY = 0;
6304  AnsiString ExistingText = "";
6306  TFont *ExistingTextFont = new TFont;
6307  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6308  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6309  if(!TextHandler->TextVector.empty())
6310  {
6311  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6312  {
6313  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6314  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6315  {
6316  ExistingText = TextPtr->TextString;
6317  ExistingTextFont->Assign(TextPtr->Font);
6318  ExistingTextHPos = TextPtr->HPos;
6319  ExistingTextVPos = TextPtr->VPos;
6320  TextFoundFlag = true;
6321  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6322  break;
6323  } // if ....
6324  } // for TextPtr...
6325  } // if !TextVector...
6326 
6327  if(TextFoundFlag)
6328  {
6329  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6330  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6331  TextBox->Font->Assign(ExistingTextFont);
6332  Display->SetFont(ExistingTextFont);
6333  Text_X = ExistingTextHPos;
6334  Text_Y = ExistingTextVPos;
6335  }
6336  else
6337  {
6338  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6339  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6340  TextBox->Font->Assign(Display->GetFont());
6341  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6342  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6343  }
6344  TextBox->Visible = true;
6345  TextBox->SetFocus();
6346  if(TextFoundFlag)
6347  TextBox->Text = ExistingText;
6348  else
6349  TextBox->Text = "New Text: CR=end, ESC=quit";
6350  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6351  TextBox->SelectAll();
6352  delete ExistingTextFont;
6353  ClearandRebuildRailway(29); // to remove old text if replaced
6355  Utilities->CallLogPop(1775);
6356  return; // If text input go no further
6357  }
6358 
6360  {
6361  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6363  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6364  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6365  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6366  // StartX = X + (Display->DisplayOffsetH * 16);
6367  // StartY = Y + (Display->DisplayOffsetV * 16);
6370  if(!TextFoundFlag) // give precedence to text
6371  {
6373  }
6374  Utilities->CallLogPop(53);
6375  return; // if text move selected don't permit anything else
6376  }
6377 
6378  else if(Level2TrackMode == TrackSelecting)
6379 /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6380  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6381  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6382  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6383  selected rectangle.
6384 */
6385  {
6386  TrainController->LogEvent("mbLeft + TrackSelecting");
6387  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6388  SelectStartPair.first = HLoc;
6389  SelectStartPair.second = VLoc;
6390  }
6391 
6392  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6393 /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6394  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6395  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6396  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6397 */
6398  {
6399  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6401  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6402  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6403  {
6404  SelectPickedUp = false;
6405  Utilities->CallLogPop(54);
6406  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6407  }
6408  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6409  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6410  {
6411  SelectPickedUp = false;
6412  Utilities->CallLogPop(55);
6413  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6414  }
6415  else
6416  {
6417  SelectPickedUp = true;
6418  }
6421  }
6422 
6424  {
6425  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6426  ResetChangedFileDataAndCaption(15, false);
6427 // RlyFile = false; - don't alter this just for PrefDir changes
6428  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6429  {
6433  }
6434  Utilities->CallLogPop(56);
6435  return;
6436  }
6437 
6439  {
6440  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6441  ResetChangedFileDataAndCaption(16, false);
6442 // RlyFile = false; - don't alter this just for PrefDir changes
6443  bool FinishElement;
6444  Screen->Cursor = TCursor(-11); // Hourglass;
6445  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6446  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6447  { // not same as start element
6448  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6449  {
6451  if(FinishElement)
6452  {
6453  ShowMessage("Preferred direction added");
6456  SetLevel1Mode(16);
6457  Screen->Cursor = TCursor(-2); // Arrow
6458  Utilities->CallLogPop(57);
6459  return;
6460  }
6461  else
6462  {
6465  }
6466  // set again since 1st time
6467  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6468  // to do the checks for Loop & End for each element as it is added
6469  }
6470  }
6471  else // same as start element
6472  {
6475  SetLevel1Mode(121);
6476  Screen->Cursor = TCursor(-2); // Arrow
6477  Utilities->CallLogPop(1714);
6478  return;
6479  }
6480  Screen->Cursor = TCursor(-2); // Arrow
6481  Utilities->CallLogPop(58);
6482  return;
6483  }
6484 
6486  {
6487  TrainController->LogEvent("mbLeft + PrefDirSelecting");
6488  ClearandRebuildRailway(56); // to get rid of earlier rectangles
6489  SelectStartPair.first = HLoc;
6490  SelectStartPair.second = VLoc;
6491  }
6492 
6493  else if(Level1Mode == OperMode)
6494  {
6495  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
6496  {
6497  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
6498  int Position;
6499  TTrackElement TrackElement;
6500  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
6501  {
6502  if(TrackElement.TrackType != SignalPost)
6503  {
6504  CallingOnButton->Down = false;
6505 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
6507  Utilities->CallLogPop(59);
6508  return;
6509  }
6510  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
6511  {
6513  {
6515  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
6517  {
6518  // found it!
6519 /*
6520  if(TrackElement.SpeedTag == 68)
6521  {
6522  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
6523  }
6524  if(TrackElement.SpeedTag == 69)
6525  {
6526  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
6527  }
6528  if(TrackElement.SpeedTag == 70)
6529  {
6530  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
6531  }
6532  if(TrackElement.SpeedTag == 71)
6533  {
6534  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
6535  }
6536  if(TrackElement.SpeedTag == 72)
6537  {
6538  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
6539  }
6540  if(TrackElement.SpeedTag == 73)
6541  {
6542  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
6543  }
6544  if(TrackElement.SpeedTag == 74)
6545  {
6546  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
6547  }
6548  if(TrackElement.SpeedTag == 75)
6549  {
6550  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
6551  }
6552 */
6553  Track->TrackElementAt(430, Position).CallingOnSet = true;
6554  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
6555 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
6556  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
6557  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
6560  CallingOnButton->Down = false;
6562 
6563 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
6564 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
6565 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
6566  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
6567  {
6568  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
6569  {
6570  // only allow route element to be removed if not selected for a route start otherwise
6571  // StartSelectionRouteID will be set & will fail at convert
6573  {
6575  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
6576  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
6577  AnsiString(PDE.VLoc));
6578  }
6579  }
6580  }
6581 
6582 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
6583  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
6584  {
6585  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
6586  { // found it
6587  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
6588  // if RouteOrPartRouteSet false then set an unrestricted route into platform
6589  {
6590  bool PointsChanged = false;
6591  IDInt ReqPosRouteID(-1);
6592  TOneRoute *NewRoute = new TOneRoute;
6593  bool CallonTrue = true;
6594  bool ConsecSignalsRouteFalse = false;
6595  if(NewRoute->GetNonPreferredRouteStartElement(1,
6596  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
6597  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, ConsecSignalsRouteFalse,
6598  CallonTrue))
6599  {
6600  if(NewRoute->GetNextNonPreferredRouteElement(1,
6601  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
6602  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, ConsecSignalsRouteFalse,
6603  CallonTrue, ReqPosRouteID, PointsChanged))
6604  {
6605  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
6606  {
6607  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
6608  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
6609  }
6610  }
6611  }
6612  delete NewRoute;
6613  }
6614  }
6615  }
6616 // InfoPanel->Visible = false;
6617  Utilities->CallLogPop(60);
6618  return;
6619  }
6620  }
6621  }
6622  }
6623  CallingOnButton->Down = false;
6625  Utilities->CallLogPop(61);
6626  return;
6627  }
6628 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
6629  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
6630  If any of above conditions not met then treat as route selection, setting route flasher if
6631  route continuing.
6632 */
6633 
6634  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
6635  // disallow route setting if paused
6636  {
6637  if(Level2OperMode == PreStart)
6638  {
6639  PointsFlashDuration = 0.0;
6642  }
6643  else
6644  {
6645  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6646  if(TTClockSpeed < 1)
6647  TempSpeedVal = TTClockSpeed;
6648  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6651  }
6652  if(RouteMode == RouteNotStarted)
6653  {
6654  TrainController->LogEvent("mbLeft + RouteNotStarted");
6655  int Position;
6656  TTrackElement TrackElement;
6657  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
6658  {
6659  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
6661  // Flash selected points & changeover if appropriate
6662  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
6663  // to ensure user only does one thing at a time
6664  {
6665  if(TrackElement.TrainIDOnElement > -1)
6666  {
6667  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
6668  Utilities->CallLogPop(62);
6669  return;
6670  }
6671  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6672 
6673 /*
6674  This used to try to allow any linked trailing edges to cause both points to change, but no good if
6675  there are two adjacent crossovers, where both trailing edges are linked to two different points.
6676  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
6677  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
6678  ensures that there are no obscure links. Hence better to stick with original.
6679 
6680  //check if trailing edge linked to another point trailing edge
6681  int DivergingPosition = TrackElement.Conn[1];
6682  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
6683  DivergingPointVectorPosition = -1;
6684  if((DivergingElement.TrackType == Points) &&
6685  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6686  {
6687  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6688  {
6689  ShowMessage("Linked points Locked");
6690  }
6691  else DivergingPointVectorPosition = DivergingPosition;
6692  }
6693  else
6694  {
6695  DivergingPosition = TrackElement.Conn[3];
6696  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
6697  if((DivergingElement.TrackType == Points) &&
6698  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6699  {
6700  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6701  {
6702  ShowMessage("Linked points locked");
6703  }
6704  else DivergingPointVectorPosition = DivergingPosition;
6705  }
6706  }
6707  Track->PointFlashFlag = true;
6708  PointFlashVectorPosition = Position;
6709  PointFlashStartTime = TrainController->TTClockTime;
6710  [close curly bracket - if include it matches earlier non-commented one!]
6711 */
6712  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
6713  int DivergingPosition = TrackElement.Conn[3];
6714  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
6715  DivergingPosition))) // full match inc same attributes
6716  {
6717  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
6718  {
6719  TrainController->StopTTClockMessage(2, "Linked points locked");
6720  }
6721  else
6722  {
6723  Track->PointFlashFlag = true;
6724  PointFlashVectorPosition = Position;
6725  DivergingPointVectorPosition = DivergingPosition;
6727  }
6728  }
6729  else // no matching point, just change this point
6730  {
6731  Track->PointFlashFlag = true;
6732  PointFlashVectorPosition = Position;
6735  }
6736  }
6737 /* drop manual changing of level crossings - only allow changing by setting a route through them
6738  else if((Track->IsLCAtHV(23, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag))//level crossing
6739  {
6740  TTrack::TFlashLevelCrossing FLC;
6741  FLC.LCHLoc = HLoc;
6742  FLC.LCVLoc = VLoc;
6743  FLC.LCChangeStartTime = TrainController->TTClockTime;
6744  FLC.LCBaseElementSpeedTag = TrackElement.SpeedTag;
6745  if(Track->IsLCBarrierDownAtHV(0, HLoc, VLoc))
6746  {
6747  FLC.LCChangeDuration = LevelCrossingBarrierUpFlashDuration;
6748  FLC.BarrierState = TTrack::Raising;
6749  }
6750  else
6751  {
6752  FLC.LCChangeDuration = LevelCrossingBarrierDownFlashDuration;
6753  FLC.BarrierState = TTrack::Lowering;
6754  }
6755  Track->SetLinkedLevelCrossingBarrierAttributes(, HLoc, VLoc, 2);//set attr to 2 for changing state
6756  Track->ChangingLCVector.push_back(FLC);
6757  }
6758 */ else // route start
6759  {
6760  if(AutoSigsFlag)
6761  {
6762  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6764  }
6765  else if(ConsecSignalsRoute)
6766  {
6767  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6769  }
6770  else
6771  {
6772  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6774  }
6775  if(PreferredRoute)
6776  {
6777  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
6778  // another route building
6779  {
6780  ConstructRoute->ClearRoute(); // in case not empty though should be
6782  {
6783  if(AutoSigsFlag)
6785  else
6788  InfoPanel->Visible = true;
6789  if(Level2OperMode == PreStart)
6790  InfoPanel->Caption = "PRE-START: Select next route location";
6791  else
6792  InfoPanel->Caption = "OPERATING: Select next route location";
6793  }
6794  }
6795  Utilities->CallLogPop(63);
6796  return;
6797  }
6798  else // nonpreferred route
6799  {
6800  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
6801  // another route building
6802  {
6803  ConstructRoute->ClearRoute(); // in case not empty though should be
6804  bool CallonFalse = false;
6805  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, ConsecSignalsRoute, CallonFalse))
6806  {
6809  InfoPanel->Visible = true;
6810  if(Level2OperMode == PreStart)
6811  InfoPanel->Caption = "PRE-START: Select next route location";
6812  else
6813  InfoPanel->Caption = "OPERATING: Select next route location";
6814  }
6815  }
6816  Utilities->CallLogPop(64);
6817  return;
6818  } // NonPreferred route
6819  } // TrackType != Points
6820  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
6821  } // if(RouteMode == RouteNotStarted)
6822  else // RouteContinuing
6823  {
6824  TrainController->LogEvent("mbLeft + RouteContinuing");
6825  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6828  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
6829  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
6830  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
6831  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
6832  // element, but this sets it to an hourglass while searching
6833  bool PointsChanged = false;
6834  if(PreferredRoute)
6835  {
6836  // route added to AllRoutes in GetNextRouteElement if valid
6837  // int ReqPosRouteNumber;
6839  ConstructRoute->ReqPosRouteID, PointsChanged))
6840  {
6841  Track->RouteFlashFlag = true;
6842  PreferredRouteFlag = true;
6843  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6844  if(TTClockSpeed < 1)
6845  TempSpeedVal = TTClockSpeed;
6846  if(Level2OperMode == PreStart)
6847  RouteFlashDuration = 0.0;
6848  else if(PointsChanged)
6849  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6850  else
6851  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
6852  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for ConsecSignalsRoute
6854  }
6855  else
6856  {
6858  }
6859  Screen->Cursor = TCursor(-2); // Arrow
6860  TrainController->BaseTime = TDateTime::CurrentDateTime();
6862  Utilities->CallLogPop(65);
6863  return;
6864  }
6865  else
6866  {
6867  bool CallonFalse = false;
6869  PointsChanged))
6870  {
6871  Track->RouteFlashFlag = true;
6872  PreferredRouteFlag = false;
6873  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6874  if(TTClockSpeed < 1)
6875  TempSpeedVal = TTClockSpeed;
6876  if(Level2OperMode == PreStart)
6877  RouteFlashDuration = 0.0;
6878  else if(PointsChanged)
6879  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6880  else
6881  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
6882  ConstructRoute->SetRouteFlashValues(2, false, false);
6884  }
6885  else
6886  {
6888  }
6889  }
6890  TrainController->BaseTime = TDateTime::CurrentDateTime();
6892  Screen->Cursor = TCursor(-2); // Arrow
6893  }
6894  Utilities->CallLogPop(66);
6895  return;
6896  }
6897  }
6898 
6899  Utilities->CallLogPop(68);
6900  }
6901  catch(const Exception &e)
6902  {
6903  ErrorLog(20, e.Message);
6904  }
6905 }
6906 
6907 // ---------------------------------------------------------------------------
6908 
6909 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
6910  // ZoomOut mode
6911 {
6912 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
6913  try
6914  {
6915  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
6916  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
6917  "," + AnsiString(Y));
6918  if(Button != mbLeft)
6919  {
6920  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
6923  WholeRailwayMoving = true;
6924  Screen->Cursor = TCursor(-22); // Four arrows;
6925  }
6926  else
6927  {
6928  InfoPanel->Visible = false; // reset infopanel in case not set later
6929  InfoPanel->Caption = "";
6930  int HRounding, VRounding;
6931  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
6932  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
6933  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
6934  if(TruePosH < 0)
6935  HRounding = -(Utilities->ScreenElementWidth / 4);
6936  else
6937  HRounding = (Utilities->ScreenElementWidth / 4);
6938  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
6939  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
6940  CentreH -= (Utilities->ScreenElementWidth / 2);
6941  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
6942  CentreH += (Utilities->ScreenElementWidth / 2);
6943  if(TruePosV < 0)
6944  VRounding = -(Utilities->ScreenElementHeight / 4);
6945  else
6946  VRounding = (Utilities->ScreenElementHeight / 4);
6947  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
6948  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
6949  CentreV -= (Utilities->ScreenElementHeight / 2);
6950  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
6951  CentreV += (Utilities->ScreenElementHeight / 2);
6952  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
6954 
6955  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
6956  if(Level1Mode == BaseMode)
6957  SetLevel1Mode(17);
6958  else if(Level1Mode == TrackMode)
6959  {
6960  // set edit menu items
6962  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
6963  // displayed gap, user wants to display the clicked area
6964  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
6965  PreventGapOffsetResetting = false;
6966  }
6967  else if(Level1Mode == PrefDirMode)
6968  {
6970  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
6971  else
6972  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
6973  }
6974  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
6975  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
6976  else if(Level1Mode == TimetableMode)
6977  {
6978  InfoPanel->Visible = false;
6979  }
6980  // Not OperMode or RestartSessionOperMode as that resets the performance file
6981  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
6982  {
6983  OperateButton->Enabled = true;
6984  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
6985  ExitOperationButton->Enabled = true;
6987  }
6988  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
6989  {
6990  OperateButton->Enabled = true;
6991  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
6992  ExitOperationButton->Enabled = true;
6993  TTClockAdjButton->Enabled = true;
6996  }
6997  else if(TempLevel2OperMode == PreStart)
6998  {
6999  OperateButton->Enabled = true;
7000  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7001  ExitOperationButton->Enabled = true;
7002  TTClockAdjButton->Enabled = true;
7004  }
7005  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7008  }
7009  Utilities->CallLogPop(69);
7010  }
7011  catch(const Exception &e)
7012  {
7013  ErrorLog(21, e.Message);
7014  }
7015 }
7016 
7017 // ---------------------------------------------------------------------------
7018 
7019 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7020 {
7021  try
7022  {
7023  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7024  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7025 
7026  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7027  {
7028  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7030  if(X < 0)
7031  X = 0; // ensure pointer stays within display area
7032  if(X > (MainScreen->Width - 1))
7033  X = MainScreen->Width - 1;
7034  if(Y < 0)
7035  Y = 0;
7036  if(Y > (MainScreen->Height - 1))
7037  Y = MainScreen->Height - 1;
7038 
7039  if(!Display->ZoomOutFlag)
7040  {
7041  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7042  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7043  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7044  {
7045  int NewH = X - StartWholeRailwayMoveHPos;
7046  int NewV = Y - StartWholeRailwayMoveVPos;
7047  Display->DisplayOffsetH -= NewH / 16;
7048  Display->DisplayOffsetV -= NewV / 16;
7049  StartWholeRailwayMoveHPos = X - StartOffsetX;
7050  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7053  {
7055  }
7056  }
7057  }
7058 
7059  else
7060  {
7061  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7062  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7063  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7064  {
7065  int NewH = X - StartWholeRailwayMoveHPos;
7066  int NewV = Y - StartWholeRailwayMoveVPos;
7067  Display->DisplayZoomOutOffsetH -= NewH / 4;
7068  Display->DisplayZoomOutOffsetV -= NewV / 4;
7069  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7070  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7071  Display->ClearDisplay(10);
7073  }
7074  }
7075  TrainController->BaseTime = TDateTime::CurrentDateTime();
7077  }
7078 
7079  else if(mbLeftDown)
7080  {
7082 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7083  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7084  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7085  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7086  selected rectangle.
7087  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7088  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7089  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7090  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7091  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7092  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7093  the selection.
7094 */
7095  {
7096  TrainController->LogEvent("MouseMove + TrackSelecting");
7097  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7098  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7099  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7100  // rightmost point and the VLoc value of the bottommost point
7101  if(CurrentHLoc >= StartHLoc)
7102  CurrentHLoc++;
7103  else
7104  StartHLoc++;
7105  if(CurrentVLoc >= StartVLoc)
7106  CurrentVLoc++;
7107  else
7108  StartVLoc++;
7109  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7111  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7113  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7114  CurrentHLoc = Display->DisplayOffsetH;
7115  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7116  CurrentVLoc = Display->DisplayOffsetV;
7117  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7118  ClearandRebuildRailway(14); // to clear earlier rectangles
7119  Display->PlotDashedRect(0, TempRect);
7120  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7121  }
7122 
7124  {
7125  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7126 
7127  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7128  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7129  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7130  // rightmost point and the VLoc value of the bottommost point
7131  if(CurrentHLoc >= StartHLoc)
7132  CurrentHLoc++;
7133  else
7134  StartHLoc++;
7135  if(CurrentVLoc >= StartVLoc)
7136  CurrentVLoc++;
7137  else
7138  StartVLoc++;
7139  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7141  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7143  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7144  CurrentHLoc = Display->DisplayOffsetH;
7145  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7146  CurrentVLoc = Display->DisplayOffsetV;
7147  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7148  ClearandRebuildRailway(57); // to clear earlier rectangles
7149  Display->PlotDashedRect(2, TempRect);
7150  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7151  }
7152 
7154 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7155  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7156  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7157  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7158  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7159  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7160  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7161  occupies. Clearand... is called finally to clear earlier selection displays.
7162 */
7163  {
7164  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7165  if(X < 0)
7166  X = 0; // ensure pointer stays within display area
7167  if(X > (MainScreen->Width - 1))
7168  X = MainScreen->Width - 1;
7169  if(Y < 0)
7170  Y = 0;
7171  if(Y > (MainScreen->Height - 1))
7172  Y = MainScreen->Height - 1;
7175  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7176  }
7177 
7179  {
7180  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7182  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7184  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7185 
7186  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7187  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7189  }
7190 
7192  {
7193  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7195  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7197  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7198 
7202  }
7203  }
7204  Utilities->CallLogPop(70);
7205  }
7206  catch(const Exception &e)
7207  {
7208  ErrorLog(22, e.Message);
7209  }
7210 }
7211 
7212 // ---------------------------------------------------------------------------
7213 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7214 {
7215 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7216  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7217  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7218  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7219  selected rectangle.
7220  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7221  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7222  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7223  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7224  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7225  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7226  the selection.
7227  [New] This function can take some time so an houglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7228  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7229  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7230  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7231  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7232  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7233  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7234  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7235  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7236  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7237  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7238  to an arrow.
7239 */
7240  try
7241  {
7242  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7243  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7244  WholeRailwayMoving = false; // added at v2.1.0
7245  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7247  {
7248  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7249  Screen->Cursor = TCursor(-11); // Hourglass;
7250  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7251  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7252 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7253 // rightmost point and the VLoc value of the bottommost point
7254  if(EndHLoc >= StartHLoc)
7255  EndHLoc++;
7256  else
7257  StartHLoc++;
7258  if(EndVLoc >= StartVLoc)
7259  EndVLoc++;
7260  else
7261  StartVLoc++;
7262  if(StartHLoc >= EndHLoc)
7263  {
7264  SelectRect.left = EndHLoc;
7265  SelectRect.right = StartHLoc;
7266  }
7267  else
7268  {
7269  SelectRect.left = StartHLoc;
7270  SelectRect.right = EndHLoc;
7271  }
7272  if(StartVLoc >= EndVLoc)
7273  {
7274  SelectRect.top = EndVLoc;
7275  SelectRect.bottom = StartVLoc;
7276  }
7277  else
7278  {
7279  SelectRect.top = StartVLoc;
7280  SelectRect.bottom = EndVLoc;
7281  }
7286  if(SelectRect.left - Display->DisplayOffsetH < 0)
7288  if(SelectRect.top - Display->DisplayOffsetV < 0)
7293  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7294  {
7295  SelectionValid = false;
7297  mbLeftDown = false;
7298  Screen->Cursor = TCursor(-2); // Arrow;
7299  Utilities->CallLogPop(71);
7300  return; // no rectangle
7301  }
7302  else
7303  {
7304  ReselectMenuItem->Enabled = false;
7305  CutMenuItem->Enabled = true;
7306  CopyMenuItem->Enabled = true;
7307  FlipMenuItem->Enabled = true;
7308  MirrorMenuItem->Enabled = true;
7309  RotRightMenuItem->Enabled = true;
7310  RotLeftMenuItem->Enabled = true;
7311  RotateMenuItem->Enabled = true;
7312  PasteMenuItem->Enabled = false;
7313 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting
7314  DeleteMenuItem->Enabled = true;
7315  if(Track->IsTrackFinished())
7316  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
7317  else
7318  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
7319  SelectBiDirPrefDirsMenuItem->Visible = false;
7320  CancelSelectionMenuItem->Enabled = true;
7321  // set SelectBitmap
7322  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
7323  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
7324 
7325  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
7326  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
7327  {
7328  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
7329  {
7330  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
7331  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
7332  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
7333  }
7334  }
7335 
7336  // store elements in Track->SelectVector, active elements first then inactive so active element plotted first during paste
7337  // clear the vector first
7339  TTrackElement TempElement; // default element
7340  bool FoundFlag;
7341  for(int x = SelectRect.left; x < SelectRect.right; x++)
7342  {
7343  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7344  {
7345  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
7346  if(FoundFlag)
7347  {
7348  TempElement = Track->TrackElementAt(440, ATVecPos);
7349  if(TempElement.SpeedTag > 0)
7350  Track->SelectPush(TempElement); // don't store erase elements
7351  }
7352  }
7353  }
7354  // now store inactive elements
7355  for(int x = SelectRect.left; x < SelectRect.right; x++)
7356  {
7357  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7358  {
7359  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
7360  if(FoundFlag)
7361  {
7362  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
7363  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
7364  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
7365  {
7366  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
7367  Track->SelectPush(TempElement);
7368  }
7369  }
7370  }
7371  }
7372  // store text items
7373  int LowSelectHPos = SelectRect.left * 16;
7374  int HighSelectHPos = SelectRect.right * 16;
7375  int LowSelectVPos = SelectRect.top * 16;
7376  int HighSelectVPos = SelectRect.bottom * 16;
7377  TextHandler->SelectTextVector.clear();
7378  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
7379  {
7380  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
7381  {
7382  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
7383  HighSelectVPos))
7384  {
7385  // have to create a new TextItem in order to create a new Font object
7386  // BUT: only create new items where they don't appear as named location names
7387  // in SelectVector, since those names shouldn't be copied or pasted.
7388  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
7389  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
7390  bool SelectVectorNamedElement = false;
7391  AnsiString SelectTextString; // new at v2.2.0
7392  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
7393  {
7394  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
7395  {
7396  SelectVectorNamedElement = true;
7397  break;
7398  }
7399  }
7400  if(SelectVectorNamedElement) // changed at v2.2.0
7401  {
7402  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
7403  }
7404  else // new at v2.2.0
7405  {
7406  SelectTextString = TextPtr->TextString;
7407  }
7408  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
7409  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
7410  }
7411  }
7412  }
7413  // store graphic items, but first clear SelectGraphicVector
7414  Track->SelectGraphicVector.clear();
7415  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
7416  {
7417  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
7418  UserGraphicPtr++)
7419  {
7420  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
7421  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
7422  {
7423  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
7424  }
7425  }
7426  }
7427 // new method - direct copying of existing selection so text included
7428  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
7429  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
7430  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
7431  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
7432  SelectionValid = true;
7433  }
7434  Screen->Cursor = TCursor(-2); // Arrow;
7435  }
7436 
7438  {
7439  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
7440  Screen->Cursor = TCursor(-11); // Hourglass;
7441 
7442  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7443  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7444 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7445 // rightmost point and the VLoc value of the bottommost point
7446  if(EndHLoc >= StartHLoc)
7447  EndHLoc++;
7448  else
7449  StartHLoc++;
7450  if(EndVLoc >= StartVLoc)
7451  EndVLoc++;
7452  else
7453  StartVLoc++;
7454  if(StartHLoc >= EndHLoc)
7455  {
7456  SelectRect.left = EndHLoc;
7457  SelectRect.right = StartHLoc;
7458  }
7459  else
7460  {
7461  SelectRect.left = StartHLoc;
7462  SelectRect.right = EndHLoc;
7463  }
7464  if(StartVLoc >= EndVLoc)
7465  {
7466  SelectRect.top = EndVLoc;
7467  SelectRect.bottom = StartVLoc;
7468  }
7469  else
7470  {
7471  SelectRect.top = StartVLoc;
7472  SelectRect.bottom = EndVLoc;
7473  }
7478  if(SelectRect.left - Display->DisplayOffsetH < 0)
7480  if(SelectRect.top - Display->DisplayOffsetV < 0)
7485  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7486  {
7488  mbLeftDown = false;
7489  Screen->Cursor = TCursor(-2); // Arrow;
7490  Utilities->CallLogPop(1551);
7491  return; // no rectangle
7492  }
7493  else
7494  {
7495  SelectBiDirPrefDirsMenuItem->Enabled = true;
7496  CancelSelectionMenuItem->Enabled = true;
7497  // don't need SelectBitmap for PrefDir selection
7498 
7499  // store active elements in Track->SelectVector, ignore inactive elements
7500  // clear the vector first
7502  TTrackElement TempElement; // default element
7503  bool FoundFlag;
7504  for(int x = SelectRect.left; x < SelectRect.right; x++)
7505  {
7506  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7507  {
7508  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
7509  if(FoundFlag)
7510  {
7511  TempElement = Track->TrackElementAt(729, ATVecPos);
7512  if(TempElement.SpeedTag > 0)
7513  Track->SelectPush(TempElement); // don't store erase elements
7514  }
7515  }
7516  }
7517  }
7518  Screen->Cursor = TCursor(-2); // Arrow;
7519  }
7520 
7522 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7523  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7524  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7525  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7526  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7527  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7528  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7529  occupies. Clearand... is called finally to clear earlier selection displays.
7530  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
7531  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
7532  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
7533 */
7534  {
7535  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
7538  }
7539 
7540  mbLeftDown = false;
7541  Track->CalcHLocMinEtc(11);
7542  Utilities->CallLogPop(72);
7543  }
7544  catch(const Exception &e)
7545  {
7546  ErrorLog(23, e.Message);
7547  }
7548 }
7549 
7550 // ---------------------------------------------------------------------------
7551 
7552 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
7553 {
7554  try
7555  {
7556  // don't call LogEvent here as would occur too often
7557  // have to allow in zoomout mode
7558  if(ErrorLogCalledFlag)
7559  return; // don't continue after an error
7560 
7561  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
7562  // put counter outside Clock2 as that may be missed
7563  LCResetCounter++;
7564 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
7565  if(LCResetCounter > 19)
7566  LCResetCounter = 0;
7568  if(WarningFlashCount > 4)
7569  WarningFlashCount = 0;
7570  if(WarningFlashCount == 0)
7571  {
7573  }
7574 
7575  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
7576  {
7577  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
7578  }
7579 
7581  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
7582  {
7583  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
7584  // BaseTime is CurrentDateTime() when operation restarts
7585 
7586 // clock speed multiplier
7587  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
7588  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
7589 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
7590  }
7591 
7592  TotalTicks++;
7594  {
7595  MissedTicks++;
7596  Utilities->CallLogPop(774);
7597  return;
7598  }
7599  Utilities->Clock2Stopped = true; //don't allow overlapping calls
7600  ClockTimer2(0);
7601  Utilities->Clock2Stopped = false;
7602  Utilities->CallLogPop(73);
7603  }
7604  catch(const Exception &e)
7605  {
7606  ErrorLog(24, e.Message);
7607  }
7608 }
7609 
7610 // ---------------------------------------------------------------------------
7611 
7612 void TInterface::ClockTimer2(int Caller)
7613 {
7614 // called every 50mSec
7615  try
7616  {
7617  // have to allow in zoomout mode
7618  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
7619 
7620  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
7621  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
7622 
7623 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
7624  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
7625  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
7626 
7627  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
7628 
7629  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
7630  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
7631  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
7632  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
7633 
7634  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
7635  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
7636  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
7637  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
7638  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
7639  {
7640  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
7641  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
7642  if(ClockTimer2Count == 0)
7643  {
7644  RestoreFocusPanel->Visible = true;
7645  RestoreFocusPanel->Enabled = true;
7646  RestoreFocusPanel->BringToFront();
7647  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
7648  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
7649  RestoreFocusPanel->Visible = false;
7650  }
7651  }
7652  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
7653 */
7654 
7655  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
7656  // toggled by 'Ctrl Alt 2' when Interface form has focus
7657 
7658  // set current time
7659  TDateTime Now = TrainController->TTClockTime;
7660 
7665 
7666  if(OperatorActionPanel->Visible)
7670  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
7671 
7672  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
7674  {
7676  }
7677 
7678 // Update Displayed Clock - resets to 0 at 96hours
7680 
7681 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
7682 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
7683 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
7684  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
7685  {
7686  WholeRailwayMoving = false;
7687  Screen->Cursor = TCursor(-2); // Arrow
7688  }
7689 
7690 // save session if required
7691  if(SaveSessionFlag)
7692  {
7693  SaveSession(0);
7694  SaveSessionFlag = false;
7695  }
7696 // load session if required
7697  if(LoadSessionFlag)
7698  {
7699  if(ClearEverything(3))
7700  {
7701  LoadSession(0);
7702  }
7703  LoadSessionFlag = false;
7704  }
7705 
7706 // check if any LCs need barriers raising
7707 
7709  {
7711  {
7712  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--)
7713  {
7714  bool TrainPresent = false;
7716  TrainPresent))
7717  {
7718  if(TrainPresent)
7719  {
7720  Track->BarriersDownVector.at(x).TrainPassed = true;
7721  }
7722  }
7723  else
7724  {
7725  Track->LCChangeFlag = true;
7727  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7728  TDateTime TempExcessLCDownTime;
7729  if(Track->BarriersDownVector.at(x).TrainPassed)
7730  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7731  else
7732  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7733  if(TempExcessLCDownTime > TDateTime(0))
7734  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7735 
7736  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7739  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7740  Track->ChangingLCVector.push_back(CLC);
7741  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
7742  }
7743  }
7744  }
7745  }
7746 // clear LCChangeFlag if no LCs changing
7747  if(Track->ChangingLCVector.empty())
7748  {
7749  Track->LCChangeFlag = false;
7750  }
7751 
7752 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
7753 // element it may be removed prior to conversion & cause an error
7754 
7755 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
7756 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
7757 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
7758 // this, it shouldn't interfere with operation.
7760  {
7761  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
7762  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
7763  {
7764  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
7765  {
7766  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
7767  // set & will fail at convert
7769  {
7771  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
7772  ElementRemovedFlag = true;
7773  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
7774  }
7775  }
7776  }
7777  if(!Display->ZoomOutFlag && ElementRemovedFlag)
7778  {
7780  }
7781  // if zoomed out ignore, will display correctly when zoom in
7782  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
7783  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
7784  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
7785  }
7786 // stop clock if hover over a warning
7787  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
7788  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
7789  && OutputLog1->Caption != "";
7790  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
7791  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
7792  && OutputLog2->Caption != "";
7793  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
7794  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
7795  && OutputLog3->Caption != "";
7796  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
7797  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
7798  && OutputLog4->Caption != "";
7799  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
7800  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
7801  && OutputLog5->Caption != "";
7802  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
7803  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
7804  && OutputLog6->Caption != "";
7805  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
7806  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
7807  && OutputLog7->Caption != "";
7808  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
7809  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
7810  && OutputLog8->Caption != "";
7811  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
7812  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
7813  && OutputLog9->Caption != "";
7814  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
7815  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
7816  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
7817 
7818  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
7819  {
7820  if(!WarningHover)
7821  {
7822  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7824  WarningHover = true;
7825  }
7826  }
7827  else if(WarningHover)
7828  {
7829  WarningHover = false;
7830  TrainController->BaseTime = TDateTime::CurrentDateTime();
7832  }
7833 
7834 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
7835  if(DevelopmentPanel->Visible)
7836  {
7837  int Position;
7838  TTrackElement TrackElement;
7839  AnsiString Type[15] =
7840  {"Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
7841  "Parapet", "NamedNonStationLocation", "Erase"};
7842 
7843  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
7844  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
7845  int HLoc, VLoc;
7846  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
7847  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
7848  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
7849  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
7850  {
7851  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
7852  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
7853  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
7854  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
7855  TrackElement.ActiveTrackElementName;
7856 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
7857  }
7858  }
7859 
7860  if(Level1Mode == TimetableMode)
7861  {
7862 /*These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
7863 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version after v2.4.3 for details.
7864 
7865 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
7866 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
7867 the entry that the mouse is now on rather than the one that was chosen.
7868 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
7869 */
7870  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0)) //high order bit set to 1 when button down, so arithmetically it is negative
7871  { //TTCurrentEntryPtr == 0 when create a timetable
7872  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
7873  }
7874  if(AnyTTKeyFlagSet()) //true if any of the below flags set
7875  {
7876  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; //reset it to the value before the key press changes it (see FormKeyDown)
7877  }
7879  {
7880  PreviousTTEntryButton->Click();
7881  SetTopIndex(0);
7882  PreviousTTEntryKeyFlag = false;
7883  }
7884  else if(NextTTEntryKeyFlag)
7885  {
7886  NextTTEntryButton->Click();
7887  SetTopIndex(1);
7888  NextTTEntryKeyFlag = false;
7889  }
7890  else if(MoveTTEntryUpKeyFlag)
7891  {
7892  MoveTTEntryUpButton->Click();
7893  SetTopIndex(2);
7894  MoveTTEntryUpKeyFlag = false;
7895  }
7896  else if(MoveTTEntryDownKeyFlag)
7897  {
7898  MoveTTEntryDownButton->Click();
7899  SetTopIndex(3);
7900  MoveTTEntryDownKeyFlag = false;
7901  }
7902  else if(CopyTTEntryKeyFlag)
7903  {
7904  CopyTTEntryButton->Click();
7905  SetTopIndex(4);
7906  CopyTTEntryKeyFlag = false;
7907  }
7908  else if(CutTTEntryKeyFlag)
7909  {
7910  CutTTEntryButton->Click();
7911  SetTopIndex(5);
7912  CutTTEntryKeyFlag = false;
7913  }
7914  else if(PasteTTEntryKeyFlag)
7915  {
7916  PasteTTEntryButton->Click();
7917  SetTopIndex(6);
7918  PasteTTEntryKeyFlag = false;
7919  }
7920  else if(DeleteTTEntryKeyFlag)
7921  {
7922  DeleteTTEntryButton->Click();
7923  SetTopIndex(7);
7924  DeleteTTEntryKeyFlag = false;
7925  }
7926  else if(NewTTEntryKeyFlag)
7927  {
7928  NewTTEntryButton->Click();
7929  SetTopIndex(8);
7930  NewTTEntryKeyFlag = false;
7931  }
7932  else if(AZOrderKeyFlag)
7933  {
7934  AZOrderButton->Click();
7935  SetTopIndex(9);
7936  AZOrderKeyFlag = false;
7937  }
7939  {
7940  TTServiceSyntaxCheckButton->Click();
7941  SetTopIndex(12);
7943  }
7944  else if(ValidateTimetableKeyFlag)
7945  {
7946  ValidateTimetableButton->Click();
7947  SetTopIndex(13);
7948  ValidateTimetableKeyFlag = false;
7949  }
7950  else if(SaveTTKeyFlag)
7951  {
7952  SaveTTButton->Click();
7953  SetTopIndex(14);
7954  SaveTTKeyFlag = false;
7955  }
7956  else if(SaveTTAsKeyFlag)
7957  {
7958  SaveTTAsButton->Click();
7959  SetTopIndex(15);
7960  SaveTTAsKeyFlag = false;
7961  }
7962  else if(RestoreTTKeyFlag)
7963  {
7964  RestoreTTButton->Click();
7965  SetTopIndex(16);
7966  RestoreTTKeyFlag = false;
7967  }
7968  else if(ExportTTKeyFlag)
7969  {
7970  ExportTTButton->Click();
7971  SetTopIndex(17);
7972  ExportTTKeyFlag = false;
7973  }
7974  else if(ConflictAnalysisKeyFlag)
7975  {
7976  ConflictAnalysisButton->Click();
7977  SetTopIndex(18);
7978  ConflictAnalysisKeyFlag = false;
7979  }
7980 
7981 
7982 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
7983  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
7984  {
7986  }
7987  else
7988  {
7990  }
7991  }
7992 
7993 // set cursor
7995  {
7996  if(!TempCursorSet)
7997  {
7998  TempCursor = Screen->Cursor;
7999  TempCursorSet = true;
8000  }
8001  Screen->Cursor = TCursor(-11); // Hourglass
8002  }
8003  else
8004  {
8005  if(TempCursorSet)
8006  {
8007  Screen->Cursor = TempCursor;
8008  TempCursorSet = false;
8009  }
8010  }
8011 
8012  if(Level2OperMode == Operating)
8013  {
8014  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8015  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8017  {
8018  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8019  }
8020  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8021  }
8022 
8023  else if(Level2OperMode == Paused) //added after v2.4.3 to show actions due after a session file reloaded
8024  {
8026  {
8027  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8028  {
8030  }
8033  }
8034  }
8035 
8036 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
8037 // by examining Flash
8038  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
8039  {
8041  }
8042 
8043 // Deal with any flashing graphics
8045  {
8046  FlashingGraphics(0, Now); // only call when WarningFlash changes
8047  if(Level1Mode == OperMode)
8048  {
8049  if(WarningFlash)
8050  {
8052  {
8053  CrashImage->Visible = true;
8054  }
8056  {
8057  DerailImage->Visible = true;
8058  }
8060  {
8061  SPADImage->Visible = true;
8062  }
8064  {
8065  TrainFailedImage->Visible = true;
8066  }
8068  {
8069  CallOnImage->Visible = true;
8070  }
8072  {
8073  SignalStopImage->Visible = true;
8074  }
8076  {
8077  BufferAttentionImage->Visible = true;
8078  }
8079  }
8080  else
8081  {
8082  CrashImage->Visible = false;
8083  DerailImage->Visible = false;
8084  SPADImage->Visible = false;
8085  TrainFailedImage->Visible = false;
8086  CallOnImage->Visible = false;
8087  SignalStopImage->Visible = false;
8088  BufferAttentionImage->Visible = false;
8089  }
8090  }
8091  else
8092  {
8093  CrashImage->Visible = false;
8094  DerailImage->Visible = false;
8095  SPADImage->Visible = false;
8096  TrainFailedImage->Visible = false;
8097  CallOnImage->Visible = false;
8098  SignalStopImage->Visible = false;
8099  BufferAttentionImage->Visible = false;
8100  }
8101  } // if(WarningFlashCount == 0)
8102  // set buttons etc as appropriate
8104  // if forced route cancellation flag set redisplay to clear the cancelled route
8106  {
8108  AllRoutes->RebuildRailwayFlag = false;
8109  }
8110  // deal with approach locking
8112  // deal with ContinuationAutoSigList
8114  // FloatingLabel function
8115  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
8116  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
8117  {
8118  TrackTrainFloat(0);
8119  }
8120  else
8121  {
8122  FloatingPanel->Visible = false;
8123  }
8124  // PerformanceLog check function
8125 /*
8126  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
8127  {
8128  PerformancePanel->Visible = false;
8129  }
8130  else
8131  {
8132 */
8134  {
8135  PerformancePanel->Visible = true;
8136  }
8137  else
8138  {
8139  PerformancePanel->Visible = false;
8140  }
8141 
8143  {
8144  OperatorActionPanel->Visible = true;
8145  }
8146  else
8147  {
8148  OperatorActionPanel->Visible = false;
8149  }
8150 
8151 // }
8152 
8153  // check if a moving train is present on a route-under-construction start element & cancel it if so
8154  if(RouteMode == RouteContinuing)
8155  {
8156  bool FoundFlag;
8157  int RouteStartVecPos;
8158  if(AutoSigsFlag)
8160  FoundFlag);
8161  else if(ConsecSignalsRoute)
8162  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
8163  FoundFlag);
8164  else
8166  FoundFlag);
8167  if(FoundFlag && (RouteStartVecPos > -1))
8168  {
8169  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
8170  if(TrackElement.TrainIDOnElement > -1)
8171  {
8172  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
8173  {
8175  // replot train as above erases the front element of the train
8177  }
8178  }
8179  }
8180  }
8181  Utilities->CallLogPop(81);
8182  }
8183  catch(const Exception &e)
8184  {
8185  ErrorLog(25, e.Message);
8186  }
8187 }
8188 
8189 // ---------------------------------------------------------------------------
8190 
8191 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
8192 {
8193  try
8194  {
8195  TrainController->LogEvent("CallingOnButtonClick");
8196  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
8197  if(CallingOnButton->Down)
8198  {
8199  // CallingOnButton->Down = true;
8200  InfoPanel->Visible = true;
8201  InfoPanel->Caption = "CALLING ON: Select signal for call on";
8202  }
8203  else
8204  {
8205  // CallingOnButton->Down = false;
8207  }
8208  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
8209  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
8210  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
8211  CallingOnButton->Enabled = false;
8212 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
8213  Utilities->CallLogPop(82);
8214  }
8215  catch(const Exception &e)
8216  {
8217  ErrorLog(26, e.Message);
8218  }
8219 }
8220 
8221 // ---------------------------------------------------------------------------
8222 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
8223 {
8224  try
8225  {
8226  // have to allow in zoomout mode
8227  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8228  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8229  Screen->Cursor = TCursor(-11); // Hourglass;
8230  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8231  if(!Display->ZoomOutFlag)
8232  {
8233  if(CtrlKey)
8234  {
8235  Display->DisplayOffsetH -= 2;
8236  }
8237  else if(ShiftKey)
8238  {
8240  }
8241  else
8242  {
8244  }
8247  {
8249  }
8250  }
8251  else
8252  {
8253  if(CtrlKey)
8254  {
8256  }
8257  else if(ShiftKey)
8258  {
8260  }
8261  else
8262  {
8264  }
8265  Display->ClearDisplay(0);
8268  Track->PlotSmallRedGap(0);
8269  }
8270  ScreenLeftButton->Enabled = true;
8271  Screen->Cursor = TCursor(-2); // Arrow
8272  Utilities->CallLogPop(83);
8273  }
8274  catch(const Exception &e)
8275  {
8276  ErrorLog(27, e.Message);
8277  }
8278 }
8279 // ---------------------------------------------------------------------------
8280 
8281 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
8282 {
8283  try
8284  {
8285  // have to allow in zoomout mode
8286  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8287  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8288  Screen->Cursor = TCursor(-11); // Hourglass;
8289  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8290  if(!Display->ZoomOutFlag)
8291  {
8292  if(CtrlKey)
8293  {
8294  Display->DisplayOffsetH += 2;
8295  }
8296  else if(ShiftKey)
8297  {
8299  }
8300  else
8301  {
8303  }
8306  {
8308  }
8309  }
8310  else
8311  {
8312  if(CtrlKey)
8313  {
8315  }
8316  else if(ShiftKey)
8317  {
8319  }
8320  else
8321  {
8323  }
8324  Display->ClearDisplay(1);
8327  Track->PlotSmallRedGap(1);
8328  }
8329  ScreenRightButton->Enabled = true;
8330  Screen->Cursor = TCursor(-2); // Arrow
8331  Utilities->CallLogPop(84);
8332  }
8333  catch(const Exception &e)
8334  {
8335  ErrorLog(28, e.Message);
8336  }
8337 }
8338 // ---------------------------------------------------------------------------
8339 
8340 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
8341 {
8342  try
8343  {
8344  // have to allow in zoomout mode
8345  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8346  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8347  Screen->Cursor = TCursor(-11); // Hourglass;
8348  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8349  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
8350  if(!Display->ZoomOutFlag)
8351  {
8352  if(CtrlKey)
8353  {
8354  Display->DisplayOffsetV += 2;
8355  }
8356  else if(ShiftKey)
8357  {
8359  }
8360  else
8361  {
8363  }
8366  {
8368  }
8369  }
8370  else
8371  {
8372  if(CtrlKey)
8373  {
8375  }
8376  else if(ShiftKey)
8377  {
8379  }
8380  else
8381  {
8383  }
8384  Display->ClearDisplay(2);
8387  Track->PlotSmallRedGap(2);
8388  }
8389  ScreenDownButton->Enabled = true;
8390  Screen->Cursor = TCursor(-2); // Arrow
8391  Utilities->CallLogPop(85);
8392  }
8393  catch(const Exception &e)
8394  {
8395  ErrorLog(29, e.Message);
8396  }
8397 }
8398 // ---------------------------------------------------------------------------
8399 
8400 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
8401 {
8402  try
8403  {
8404  // have to allow in zoomout mode
8405  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8406  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8407  Screen->Cursor = TCursor(-11); // Hourglass;
8408  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8409  if(!Display->ZoomOutFlag)
8410  {
8411  if(CtrlKey)
8412  {
8413  Display->DisplayOffsetV -= 2;
8414  }
8415  else if(ShiftKey)
8416  {
8418  }
8419  else
8420  {
8422  }
8425  {
8427  }
8428  }
8429  else
8430  {
8431  if(CtrlKey)
8432  {
8434  }
8435  else if(ShiftKey)
8436  {
8438  }
8439  else
8440  {
8442  }
8443  Display->ClearDisplay(3);
8446  Track->PlotSmallRedGap(3);
8447  }
8448  ScreenUpButton->Enabled = true;
8449  Screen->Cursor = TCursor(-2); // Arrow
8450  Utilities->CallLogPop(86);
8451  }
8452  catch(const Exception &e)
8453  {
8454  ErrorLog(30, e.Message);
8455  }
8456 }
8457 // ---------------------------------------------------------------------------
8458 
8459 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
8460 {
8461  try
8462  {
8463  // have to allow in zoomout mode
8464  TrainController->LogEvent("ZoomButtonClick");
8465  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
8466  Screen->Cursor = TCursor(-11); // Hourglass;
8467  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8468  if(Display->ZoomOutFlag) // i.e resume zoomed in view
8469  {
8470  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
8471 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
8472  if(Level1Mode == BaseMode)
8473  {
8474  InfoPanel->Visible = false; // reset infopanel in case not set later
8475  InfoPanel->Caption = "";
8476  SetLevel1Mode(18);
8477  }
8478  else if(Level1Mode == TrackMode)
8479  {
8480  InfoPanel->Visible = false; // reset infopanel in case not set later
8481  InfoPanel->Caption = "";
8482  // set edit menu items
8484  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
8485  }
8486  else if(Level1Mode == PrefDirMode)
8487  {
8489  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
8490  else
8491  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
8492  }
8493 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
8494 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
8495  else if(Level1Mode == TimetableMode)
8496  {
8497  InfoPanel->Visible = false;
8498  }
8499  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
8500  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
8501  {
8502  OperateButton->Enabled = true;
8503  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
8504  ExitOperationButton->Enabled = true;
8506  }
8507  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
8508  {
8509  OperateButton->Enabled = true;
8510  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8511  ExitOperationButton->Enabled = true;
8512  TTClockAdjButton->Enabled = true;
8515  }
8516  else if(Level2OperMode == PreStart)
8517  {
8518  OperateButton->Enabled = true;
8519  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8520  ExitOperationButton->Enabled = true;
8521  TTClockAdjButton->Enabled = true;
8523  }
8524  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
8526  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
8527  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
8528  }
8529  else // set zoomed out view
8530  {
8531  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
8532  Display->ZoomOutFlag = true;
8534  FileMenu->Enabled = false;
8535  ModeMenu->Enabled = false;
8536  EditMenu->Enabled = false;
8537  TextBox->Visible = false;
8538  LocationNameTextBox->Visible = false;
8539  TTClockAdjButton->Enabled = false;
8540 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
8541  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8542  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
8543 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
8544  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
8545  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
8546  if((LeftExcess > 0) && (RightExcess > 0))
8547  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
8548  else if((LeftExcess > 0) && (RightExcess <= 0))
8549  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
8550  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
8551  else if((LeftExcess <= 0) && (RightExcess > 0))
8552  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
8553  else
8554  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
8555 
8556  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
8557  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
8558  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
8559  if((TopExcess > 0) && (BotExcess > 0))
8560  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
8561  else if((TopExcess > 0) && (BotExcess <= 0))
8562  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
8563  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
8564  else if((TopExcess <= 0) && (BotExcess > 0))
8565  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
8566  else
8567  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
8568 
8569  Display->ClearDisplay(4);
8573  Track->PlotSmallRedGap(4);
8574  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
8575  }
8576  Screen->Cursor = TCursor(-2); // Arrow
8577  ZoomButton->Enabled = true; // restore, see above
8578  Utilities->CallLogPop(87);
8579  }
8580  catch(const Exception &e)
8581  {
8582  ErrorLog(31, e.Message);
8583  }
8584 }
8585 // ---------------------------------------------------------------------------
8586 
8587 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
8588 {
8589  try
8590  {
8591  // have to allow in zoomout mode
8592  TrainController->LogEvent("HomeButtonClick");
8593  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
8594  Screen->Cursor = TCursor(-11); // Hourglass;
8595  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8596  if(!Display->ZoomOutFlag) // zoomed in mode
8597  {
8598  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
8602  {
8604  }
8605  }
8606  else
8607  {
8608  // zoomed out mode
8609  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8610  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
8612  Display->ClearDisplay(9);
8615  Track->PlotSmallRedGap(5);
8616  }
8617  Screen->Cursor = TCursor(-2); // Arrow
8618  HomeButton->Enabled = true; // restore, see above
8619  Utilities->CallLogPop(88);
8620  }
8621  catch(const Exception &e)
8622  {
8623  ErrorLog(32, e.Message);
8624  }
8625 }
8626 
8627 // ---------------------------------------------------------------------------
8628 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
8629 {
8630  try
8631  {
8632  TrainController->LogEvent("NewHomeButtonClick");
8633  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
8634  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8635  if(!Display->ZoomOutFlag) // zoomed in mode
8636  {
8639  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
8640  }
8641  else
8642  {
8645  }
8646  Utilities->CallLogPop(1188);
8647  NewHomeButton->Enabled = true; // restore, see above
8648  }
8649  catch(const Exception &e)
8650  {
8651  ErrorLog(174, e.Message);
8652  }
8653 }
8654 
8655 // ---------------------------------------------------------------------------
8656 void __fastcall TInterface::EditMenuClick(TObject *Sender)
8657  // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
8658 {
8659  try
8660  {
8661  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
8662  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
8663  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
8664  }
8665  catch(const Exception &e)
8666  {
8667  ErrorLog(196, e.Message);
8668  }
8669 }
8670 
8671 // ---------------------------------------------------------------------------
8672 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
8673 {
8674 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
8675  try
8676  {
8677  TrainController->LogEvent("SelectMenuItemClick");
8678  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
8679  if(Level1Mode == TrackMode)
8680  {
8681  SelectionValid = false;
8683  SetLevel2TrackMode(34);
8684  }
8685  else if(Level1Mode == PrefDirMode)
8686  {
8689  }
8690  Utilities->CallLogPop(1189);
8691  }
8692  catch(const Exception &e)
8693  {
8694  ErrorLog(145, e.Message);
8695  }
8696 }
8697 
8698 // ---------------------------------------------------------------------------
8699 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
8700 {
8701  try
8702  {
8703  TrainController->LogEvent("ReselectMenuItemClick");
8704  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
8705  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
8706  {
8707  Utilities->CallLogPop(1424);
8708  return;
8709  }
8710 
8711  int TLHCH = SelectBitmapHLoc;
8712  int TLHCV = SelectBitmapVLoc;
8713  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
8714  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
8715  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
8716  SelectRect = NewSelectRect;
8718  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
8719  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8720  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8721  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8722  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8723 
8724  SelectionValid = true;
8725  ReselectMenuItem->Enabled = false;
8726  CutMenuItem->Enabled = true;
8727  CopyMenuItem->Enabled = true;
8728  FlipMenuItem->Enabled = true;
8729  MirrorMenuItem->Enabled = true;
8730  RotRightMenuItem->Enabled = true;
8731  RotLeftMenuItem->Enabled = true;
8732  RotateMenuItem->Enabled = true;
8733  PasteMenuItem->Enabled = false;
8734  DeleteMenuItem->Enabled = true;
8735  if(Track->IsTrackFinished())
8736  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8737  else
8738  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8739  SelectBiDirPrefDirsMenuItem->Visible = false;
8740  CancelSelectionMenuItem->Enabled = true;
8741  mbLeftDown = false;
8742  // Level1Mode = TrackMode;
8743  // SetLevel1Mode(68);
8745  SetLevel2TrackMode(47);
8746  Utilities->CallLogPop(1425);
8747  }
8748  catch(const Exception &e)
8749  {
8750  ErrorLog(146, e.Message);
8751  }
8752 }
8753 
8754 // ---------------------------------------------------------------------------
8755 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
8756 {
8757  try
8758  {
8759  TrainController->LogEvent("CutMenuItemClick");
8760  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
8761  // Level1Mode = TrackMode;
8762  // SetLevel1Mode(69);
8764  SetLevel2TrackMode(35);
8765  Utilities->CallLogPop(1190);
8766  }
8767  catch(const Exception &e)
8768  {
8769  ErrorLog(147, e.Message);
8770  }
8771 }
8772 // ---------------------------------------------------------------------------
8773 
8774 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
8775 {
8776  try
8777  {
8778  TrainController->LogEvent("CopyMenuItemClick");
8779  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
8780  // Level1Mode = TrackMode;
8781  // SetLevel1Mode(70);
8783  SetLevel2TrackMode(36);
8784  Utilities->CallLogPop(1191);
8785  }
8786  catch(const Exception &e)
8787  {
8788  ErrorLog(148, e.Message);
8789  }
8790 }
8791 
8792 // ---------------------------------------------------------------------------
8793 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
8794 {
8795  try
8796  {
8797  TrainController->LogEvent("FlipMenuItemClick");
8798  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
8799  // reset values in SelectVector
8800  int VerSum = SelectRect.top + SelectRect.bottom - 1;
8801  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8802  {
8803  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
8804  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
8805  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
8806  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
8807  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
8808  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
8809  int HLoc = Track->SelectVectorAt(7, x).HLoc;
8811  TE.VLoc = VLoc;
8812  TE.HLoc = HLoc;
8813 
8814  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8816  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
8817  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
8820  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
8821  Track->SelectVectorAt(26, x) = TE;
8822  }
8823  // reset values in SelectTextVector
8824  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
8825  {
8827  // also subtract font height, brings position approximately right
8828  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
8829  }
8830  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
8831  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8832  {
8833  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
8834  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
8835  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
8836  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
8837  }
8839  SetLevel2TrackMode(48);
8840  Utilities->CallLogPop(1426);
8841  }
8842  catch(const Exception &e)
8843  {
8844  ErrorLog(149, e.Message);
8845  }
8846 }
8847 
8848 // ---------------------------------------------------------------------------
8849 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
8850 {
8851  try
8852  {
8853  TrainController->LogEvent("MirrorMenuItemClick");
8854  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
8855  // reset values in SelectVector
8856  int HorSum = SelectRect.left + SelectRect.right - 1;
8857  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8858  {
8859  // See note above for FlipMenuItem relating to mods for v2.2.0
8860  int VLoc = Track->SelectVectorAt(22, x).VLoc;
8861  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
8863  TE.VLoc = VLoc;
8864  TE.HLoc = HLoc;
8865 
8866  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8868  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
8869  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
8872  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
8873 
8874 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
8875  Track->SelectVectorAt(30, x) = TE;
8876 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
8877 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
8878  }
8879  // reset values in SelectTextVector
8880  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
8881  {
8883  // also subtract half font height for each letter of text, brings position approximately right
8884  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
8885  }
8886  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
8887  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8888  {
8889  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
8890  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
8891  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
8892  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
8893  {
8894  LeftPosAfterMirror = SelectRect.left * 16;
8895  }
8896  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
8897  }
8899  SetLevel2TrackMode(49);
8900  Utilities->CallLogPop(1427);
8901  }
8902  catch(const Exception &e)
8903  {
8904  ErrorLog(150, e.Message);
8905  }
8906 }
8907 
8908 // ---------------------------------------------------------------------------
8909 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
8910 {
8911  try
8912  {
8913  TrainController->LogEvent("Rotate180MenuItemClick");
8914  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
8915  // reset values in SelectVector
8916  int HorSum = SelectRect.left + SelectRect.right - 1;
8917  int VerSum = SelectRect.top + SelectRect.bottom - 1;
8918  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8919  {
8920  // See note above for FlipMenuItem relating to mods for v2.2.0
8921  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
8922  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
8924  TE.VLoc = VLoc;
8925  TE.HLoc = HLoc;
8926 
8927  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8929  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
8930  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
8933  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
8934 
8935 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
8936  Track->SelectVectorAt(34, x) = TE;
8937 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
8938 // TempEl.HLoc = HorSum - TempEl.HLoc;
8939 // TempEl.VLoc = VerSum - TempEl.VLoc;
8940 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
8941  }
8942  // reset values in SelectTextVector
8943  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
8944  {
8946  // also subtract half font height for each letter of text, brings position approximately right horizontally
8947  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
8948  // also subtract font height, brings position approximately right vertically
8949  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
8950  }
8951  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
8952  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8953  {
8954  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
8955  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
8956  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
8957  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
8958  {
8959  TopPosAfterFlip = SelectRect.top * 16;
8960  }
8961  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
8962  }
8963  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
8964  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8965  {
8966  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
8967  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
8968  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
8969  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
8970  {
8971  LeftPosAfterMirror = SelectRect.left * 16;
8972  }
8973  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
8974  }
8975  // Level1Mode = TrackMode;
8976  // SetLevel1Mode(73);
8978  SetLevel2TrackMode(50);
8979  Utilities->CallLogPop(1435);
8980  }
8981  catch(const Exception &e)
8982  {
8983  ErrorLog(151, e.Message);
8984  }
8985 }
8986 // ---------------------------------------------------------------------------
8987 
8988 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
8989 {
8990  try
8991  {
8992  TrainController->LogEvent("RotateRight90MenuItemClick");
8993  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRight90MenuItemClick");
8994  Screen->Cursor = TCursor(-11); // Hourglass
8995  // check first if a square and if not give message & quit
8996  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
8997  {
8998  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
8999  int VertSize = SelectRect.bottom - SelectRect.top;
9000  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9001  {
9002  // use right hand vertical & make square to left of that
9003  SelectRect.left = SelectRect.right - VertSize;
9004  }
9005  else
9006  {
9007  SelectRect.right = SelectRect.left + VertSize;
9008  }
9011  int button = Application->MessageBox
9012  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9013  L"Left click and hold here to move this message box", MB_OKCANCEL);
9014  if(button == IDCANCEL)
9015  {
9016  ResetSelectRect();
9017  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9018  SetLevel1Mode(133);
9020  SetLevel2TrackMode(59);
9022  Screen->Cursor = TCursor(-2); // Arrow
9023  Utilities->CallLogPop(2121);
9024  return;
9025  }
9026  }
9027  // set SelectBitmap (only need the dimensions here as not moving the selection)
9030  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9031  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9032  // store track elements and text in select vectors
9034  TTrackElement TempElement; // default element
9035  bool FoundFlag;
9036  for(int x = SelectRect.left; x < SelectRect.right; x++)
9037  {
9038  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9039  {
9040  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
9041  if(FoundFlag)
9042  {
9043  TempElement = Track->TrackElementAt(959, ATVecPos);
9044  if(TempElement.SpeedTag > 0)
9045  Track->SelectPush(TempElement);
9046  }
9047  }
9048  }
9049  // now store inactive elements
9050  for(int x = SelectRect.left; x < SelectRect.right; x++)
9051  {
9052  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9053  {
9054  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
9055  if(FoundFlag)
9056  {
9057  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
9058  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9059  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9060  {
9061  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
9062  Track->SelectPush(TempElement);
9063  }
9064  }
9065  }
9066  }
9067  // store text items
9068  int LowSelectHPos = SelectRect.left * 16;
9069  int HighSelectHPos = SelectRect.right * 16;
9070  int LowSelectVPos = SelectRect.top * 16;
9071  int HighSelectVPos = SelectRect.bottom * 16;
9072  TextHandler->SelectTextVector.clear();
9073  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9074  {
9075  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9076  {
9077  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9078  {
9079  // have to create a new TextItem in order to create a new Font object
9080  // BUT: only create new items where they don't appear as named location names
9081  // in SelectVector, since those names shouldn't be copied or pasted.
9082  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9083  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9084  bool SelectVectorNamedElement = false;
9085  AnsiString SelectTextString; // new at v2.2.0
9086  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9087  {
9088  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9089  {
9090  SelectVectorNamedElement = true;
9091  break;
9092  }
9093  }
9094  if(SelectVectorNamedElement) // changed at v2.2.0
9095  {
9096  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9097  }
9098  else // new at v2.2.0
9099  {
9100  SelectTextString = TextPtr->TextString;
9101  }
9102  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9103  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9104  }
9105  }
9106  }
9107  // store graphic items, but first clear SelectGraphicVector
9108  Track->SelectGraphicVector.clear();
9109  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9110  {
9111  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9112  UserGraphicPtr++)
9113  {
9114  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9115  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9116  {
9117  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9118  }
9119  }
9120  }
9121  // now transform the H & V for rh rotate
9122  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9123  {
9124  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
9125  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
9127  TE.VLoc = VLoc;
9128  TE.HLoc = HLoc;
9129 
9130  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9132  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
9133  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
9136  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
9137  Track->SelectVectorAt(65, x) = TE;
9138  }
9139  // reset values in SelectTextVector
9140  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
9141  {
9142 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9143 // & if a lot then some will extend beyond the selection
9145  // also subtract half font height for each letter of text, brings position approximately right horizontally
9146  TextItem->HPos = (SelectRect.left) * 16;
9147  TextItem->VPos = (SelectRect.top + x) * 16;
9148  }
9149  // reset values in SelectGraphicVector
9150  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9151  {
9152  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9153  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9154  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
9155  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
9156  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9157  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9158  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9159  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9160  }
9161  Screen->Cursor = TCursor(-2); // Arrow
9163  SetLevel2TrackMode(60);
9164  Utilities->CallLogPop(2122);
9165  }
9166  catch(const Exception &e)
9167  {
9168  ErrorLog(205, e.Message);
9169  }
9170 }
9171 
9172 // ---------------------------------------------------------------------------
9173 
9174 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
9175 {
9176  try
9177  {
9178  TrainController->LogEvent("RotateLeft90MenuItemClick");
9179  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeft90MenuItemClick");
9180  Screen->Cursor = TCursor(-11); // Hourglass;
9181  // check first if a square and if not give message & quit
9182  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9183  {
9184  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9185  int VertSize = SelectRect.bottom - SelectRect.top;
9186  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9187  {
9188  // use right hand vertical & make square to left of that
9189  SelectRect.left = SelectRect.right - VertSize;
9190  }
9191  else
9192  {
9193  SelectRect.right = SelectRect.left + VertSize;
9194  }
9197  int button = Application->MessageBox
9198  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9199  L"Left click and hold here to move this message box", MB_OKCANCEL);
9200  if(button == IDCANCEL)
9201  {
9202  ResetSelectRect();
9203  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9204  SetLevel1Mode(134);
9206  SetLevel2TrackMode(61);
9208  Screen->Cursor = TCursor(-2); // Arrow
9209  Utilities->CallLogPop(2123);
9210  return;
9211  }
9212  }
9213  // set SelectBitmap (only need the dimensions here as not moving the selection)
9216  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9217  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9218  // store track elements and text in select vectors
9220  TTrackElement TempElement; // default element
9221  bool FoundFlag;
9222  for(int x = SelectRect.left; x < SelectRect.right; x++)
9223  {
9224  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9225  {
9226  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
9227  if(FoundFlag)
9228  {
9229  TempElement = Track->TrackElementAt(960, ATVecPos);
9230  if(TempElement.SpeedTag > 0)
9231  Track->SelectPush(TempElement);
9232  }
9233  }
9234  }
9235  // now store inactive elements
9236  for(int x = SelectRect.left; x < SelectRect.right; x++)
9237  {
9238  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9239  {
9240  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
9241  if(FoundFlag)
9242  {
9243  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
9244  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9245  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9246  {
9247  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
9248  Track->SelectPush(TempElement);
9249  }
9250  }
9251  }
9252  }
9253  // store text items
9254  int LowSelectHPos = SelectRect.left * 16;
9255  int HighSelectHPos = SelectRect.right * 16;
9256  int LowSelectVPos = SelectRect.top * 16;
9257  int HighSelectVPos = SelectRect.bottom * 16;
9258  TextHandler->SelectTextVector.clear();
9259  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9260  {
9261  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9262  {
9263  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9264  {
9265  // have to create a new TextItem in order to create a new Font object
9266  // BUT: only create new items where they don't appear as named location names
9267  // in SelectVector, since those names shouldn't be copied or pasted.
9268  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9269  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9270  bool SelectVectorNamedElement = false;
9271  AnsiString SelectTextString; // new at v2.2.0
9272  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9273  {
9274  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9275  {
9276  SelectVectorNamedElement = true;
9277  break;
9278  }
9279  }
9280  if(SelectVectorNamedElement) // changed at v2.2.0
9281  {
9282  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9283  }
9284  else // new at v2.2.0
9285  {
9286  SelectTextString = TextPtr->TextString;
9287  }
9288  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9289  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9290  }
9291  }
9292  }
9293  // store graphic items, but first clear SelectGraphicVector
9294  Track->SelectGraphicVector.clear();
9295  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9296  {
9297  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9298  UserGraphicPtr++)
9299  {
9300  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9301  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9302  {
9303  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9304  }
9305  }
9306  }
9307  // now transform the H & V for lh rotate
9308  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9309  {
9310  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
9311  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
9313  TE.VLoc = VLoc;
9314  TE.HLoc = HLoc;
9315 
9316  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9318  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
9319  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
9322  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
9323  Track->SelectVectorAt(73, x) = TE;
9324  }
9325  // reset values in SelectTextVector
9326  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
9327  {
9328 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9329 // & if a lot then some will extend beyond the selection
9331  // also subtract half font height for each letter of text, brings position approximately right horizontally
9332  TextItem->HPos = (SelectRect.left) * 16;
9333  TextItem->VPos = (SelectRect.top + x) * 16;
9334  }
9335  // reset values in SelectGraphicVector
9336  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9337  {
9338  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9339  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9340  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
9341  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
9342  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9343  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9344  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9345  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9346  }
9347  Screen->Cursor = TCursor(-2); // Arrow
9349  SetLevel2TrackMode(62);
9350  Utilities->CallLogPop(2124);
9351  }
9352  catch(const Exception &e)
9353  {
9354  ErrorLog(206, e.Message);
9355  }
9356 }
9357 
9358 // ---------------------------------------------------------------------------
9359 
9360 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
9361 {
9362  try
9363  {
9364  TrainController->LogEvent("PasteMenuItemClick");
9365  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
9366  // Level1Mode = TrackMode;
9367  // SetLevel1Mode(74);
9369  SetLevel2TrackMode(58);
9370  Utilities->CallLogPop(2060);
9371  }
9372  catch(const Exception &e)
9373  {
9374  ErrorLog(198, e.Message);
9375  }
9376 }
9377 
9378 // ---------------------------------------------------------------------------
9379 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
9380 {
9381  try
9382  {
9383  TrainController->LogEvent("DeleteMenuItemClick");
9384  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
9385  // Level1Mode = TrackMode;
9386  // SetLevel1Mode(75);
9388  SetLevel2TrackMode(38);
9389  Utilities->CallLogPop(1193);
9390  }
9391  catch(const Exception &e)
9392  {
9393  ErrorLog(153, e.Message);
9394  }
9395 }
9396 // ---------------------------------------------------------------------------
9397 
9398 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
9399 {
9400  try
9401  {
9402  TrainController->LogEvent("SelectLengthsMenuItemClick");
9403  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
9404  TrackElementPanel->Visible = false;
9405  TrackLengthPanel->Visible = true;
9406  TrackLengthPanel->SetFocus();
9407  SelectLengthsFlag = true;
9408  InfoPanel->Visible = true;
9409  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
9411  {
9412  ShowMessage("Note: length value will apply to each element's track within the selection\n\nThis message will only be shown once");
9413  LengthWarningSentFlag = true;
9414  }
9415  DistanceBox->Text = "";
9416  SpeedLimitBox->Text = "";
9419  ResetChangedFileDataAndCaption(19, true); // true for NonPrefDirChangesMade
9420  Utilities->CallLogPop(1414);
9421  }
9422  catch(const Exception &e)
9423  {
9424  ErrorLog(154, e.Message);
9425  }
9426 }
9427 
9428 // ---------------------------------------------------------------------------
9429 
9430 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
9431 {
9432 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
9433  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
9434 */
9435  try
9436  {
9437  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
9438  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
9440  bool FoundFlag = false;
9441  if(Track->SelectVector.empty())
9442  {
9443  Utilities->CallLogPop(1550);
9444  return;
9445  }
9446  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9447  {
9448  TTrackElement TE = Track->SelectVectorAt(14, x);
9449  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
9450  if(FoundFlag)
9451  {
9452  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
9453  {
9454  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9456  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9458  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
9460  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
9462  }
9463  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
9464  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
9465  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
9466  // at the same position
9467  {
9468  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9470  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9472  }
9473  }
9474  }
9476  ResetChangedFileDataAndCaption(22, false);
9477  // RlyFile = false; - don't alter this just for PrefDir changes
9478  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
9479  SetLevel1Mode(30);
9481  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
9482  Utilities->CallLogPop(1549);
9483  }
9484  catch(const Exception &e)
9485  {
9486  ErrorLog(155, e.Message);
9487  }
9488 }
9489 
9490 // ---------------------------------------------------------------------------
9491 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
9492 {
9493  try
9494  {
9495  TrainController->LogEvent("CancelSelectionClick");
9496  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
9497  ClearandRebuildRailway(46); // to remove the selection outline
9498  SelectionValid = false;
9499  Track->CopyFlag = false;
9501  ResetSelectRect();
9502  if(Level1Mode == TrackMode)
9503  {
9504  SetLevel1Mode(76);
9506  SetLevel2TrackMode(39);
9507  }
9508  else if(Level1Mode == PrefDirMode)
9509  {
9510  SetLevel1Mode(32);
9511  }
9512  Utilities->CallLogPop(1413);
9513  }
9514  catch(const Exception &e)
9515  {
9516  ErrorLog(156, e.Message);
9517  }
9518 }
9519 
9520 // ---------------------------------------------------------------------------
9521 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
9522 {
9523  try
9524  {
9525  TrainController->LogEvent("LoadTimetableMenuItemClick");
9526  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
9527  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
9528  // reset all message flags, stops them being given twice new at v2.4.0
9529  TrainController->SSHigh = false;
9530  TrainController->MRSHigh = false;
9531  TrainController->MRSLow = false;
9532  TrainController->MassHigh = false;
9533  TrainController->BFHigh = false;
9534  TrainController->BFLow = false;
9535  TrainController->PwrHigh = false;
9536  TrainController->SigSHigh = false;
9537  TrainController->SigSLow = false;
9538  if(TimetableDialog->Execute())
9539  {
9540  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
9541  bool CheckLocationsExistInRailwayTrue = true;
9542  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
9543  // true for GiveMessages
9544  {
9545  Screen->Cursor = TCursor(-11); // Hourglass;
9546  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
9547  if(TTBLFile.is_open())
9548  {
9549  bool SessionFileFalse = false;
9550  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
9551  {
9552  SaveTempTimetableFile(0, TimetableDialog->FileName);
9553  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
9554  }
9555  else
9556  {
9557  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
9558  }
9559  Screen->Cursor = TCursor(-2); // Arrow
9560  } // if(TimetableIntegrityCheck
9561  else
9562  ShowMessage("Timetable preliminary integrity check failed - unable to load");
9563  } // if(TimetableDialog->Execute())
9564  // else ShowMessage("Load Aborted");
9565  Utilities->CallLogPop(752);
9566  }
9567  catch(const Exception &e)
9568  {
9569  ErrorLog(34, e.Message);
9570  }
9571 }
9572 
9573 // ---------------------------------------------------------------------------
9574 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
9575 {
9576  try
9577  {
9578  TrainController->LogEvent("SignallerControl1Click");
9579  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
9581  Train.SignallerStoppingFlag = false;
9582  Train.TrainMode = Signaller;
9583  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
9584  {
9585  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
9586  }
9587  if(Train.Stopped())
9588  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
9589  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
9591  Train.PlotTrain(5, Display);
9592  AnsiString LocName = "";
9593  if(Train.LeadElement > -1)
9594  {
9595  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
9596  }
9597  if((LocName == "") && (Train.MidElement > -1))
9598  {
9599  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
9600  }
9601 
9602  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
9603  if(Train.StoppedAtLocation && (LocName != ""))
9604  {
9605  Train.RestoreTimetableLocation = LocName;
9606  }
9607  else
9608  {
9609  Train.RestoreTimetableLocation = "";
9610  }
9611 
9612  // check whether need to offer 'pass red signal'
9613  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
9614  {
9615  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
9616  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
9617  if((NextElementPosition > -1) && (NextEntryPos > -1))
9618  {
9619  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
9620  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
9621  { // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
9622  // forwards, but don't change the background colour so still shows as stopped at location
9623  Train.StoppedAtSignal = true;
9624  }
9625  }
9626  }
9627  // find element ID if no locname
9628  if((LocName == "") && Train.LeadElement > -1)
9629  {
9630  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
9631  }
9632  if((LocName == "") && (Train.MidElement > -1))
9633  {
9634  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
9635  }
9636  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9637  Utilities->CallLogPop(1772);
9638  }
9639  catch(const Exception &e)
9640  {
9641  ErrorLog(157, e.Message);
9642  }
9643 }
9644 
9645 // ---------------------------------------------------------------------------
9646 
9647 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
9648 {
9649  try
9650  {
9651  TrainController->LogEvent("TimetableControlMenuItemClick");
9652  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
9654  Train.SignallerStoppingFlag = false;
9655  Train.TrainMode = Timetable;
9656  Train.SignallerStopped = false;
9657  Train.StoppedAfterSPAD = false;
9658  Train.SPADFlag = false;
9661 // red headcode[0]
9662  Train.PlotTrain(6, Display);
9663  AnsiString LocName = "";
9664  if(Train.LeadElement > -1)
9665  {
9666  LocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
9667  }
9668  if((LocName == "") && (Train.MidElement > -1))
9669  {
9670  LocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
9671  }
9672  if((LocName == "") && Train.LeadElement > -1)
9673  {
9674  LocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
9675  }
9676  if((LocName == "") && (Train.MidElement > -1))
9677  {
9678  LocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
9679  }
9680  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
9681  {
9682  Train.StoppedAtLocation = true;
9683  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
9684  // depart the departure time & TRS time have already been calculated so need to
9685  // force a recalculation - see below
9686  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
9687  if(!Train.TrainFailed)
9688  {
9690  }
9691  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9692  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
9693  { // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
9694  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9695  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
9696  }
9697  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
9698  { // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
9699  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9700  Train.TimeTimeLocArrived = true;
9701  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
9702  }
9703  }
9704  else
9705  {
9706  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
9707  int NextEntryPos = -1; // ---ditto---
9708  if(Train.LeadElement > -1) // ---ditto---
9709  { // ---ditto---
9710  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9711  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9712  } // ---ditto---
9713  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9714  if(!Train.TrainFailed)
9715  {
9716  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
9717  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
9718  if(Train.AbleToMove(1)) // if has no power
9719  {
9720  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
9721  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
9722  Train.FirstHalfMove = true; // ---Ditto---
9723  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
9724  {
9725  // Train.EntrySpeed = 0;
9726  // Train.EntryTime = TrainController->TTClockTime;
9727  // Train.FirstHalfMove = true;
9728  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
9729  }
9730  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
9731  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
9732  {
9733  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9734  }
9735  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
9736  {
9737  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
9738  }
9739  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
9740  {
9741  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
9742  }
9743  }
9744  else if(Train.StoppedAtSignal)
9745  {
9746  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9747  if(!Train.TrainFailed)
9748  {
9750  }
9751  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
9752  }
9753  }
9754  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9755  Utilities->CallLogPop(1195);
9756  }
9757  catch(const Exception &e)
9758  {
9759  ErrorLog(158, e.Message);
9760  }
9761 }
9762 
9763 // ---------------------------------------------------------------------------
9764 
9765 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
9766 {
9767  try
9768  {
9769  TrainController->LogEvent("ChangeDirectionMenuItemClick");
9770  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
9772  Train.SignallerStoppingFlag = false;
9773  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
9774  Train.SignallerStopped = true;
9775  AnsiString LocName = "";
9776  if(Train.LeadElement > -1)
9777  {
9778  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
9779  }
9780  if((LocName == "") && (Train.MidElement > -1))
9781  {
9782  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
9783  }
9784  if((LocName == "") && Train.LeadElement > -1)
9785  {
9786  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
9787  }
9788  if((LocName == "") && (Train.MidElement > -1))
9789  {
9790  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
9791  }
9792  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9793  Utilities->CallLogPop(1196);
9794  }
9795  catch(const Exception &e)
9796  {
9797  ErrorLog(159, e.Message);
9798  }
9799 }
9800 // ---------------------------------------------------------------------------
9801 
9802 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
9803 {
9804  try
9805  {
9806  TrainController->LogEvent("MoveForwardsMenuItemClick");
9807  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
9809  Train.SignallerStoppingFlag = false;
9810  if(!Train.AbleToMove(2))
9811  { // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
9812  Utilities->CallLogPop(1197);
9813  return;
9814  }
9815  Train.SignallerStopped = false;
9816  Train.StoppedAfterSPAD = false; // in case had been set
9817  Train.SPADFlag = false;
9818  Train.StoppedAtLocation = false; // may not have been set but reset anyway
9819  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9821  Train.EntrySpeed = 0;
9823  Train.FirstHalfMove = true;
9824  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
9825  int NextEntryPos = -1; // ---ditto---
9826  if(Train.LeadElement > -1) // ---ditto---
9827  { // ---ditto---
9828  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9829  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9830  } // ---ditto---
9831  if((NextElementPos > -1) && (NextEntryPos > -1))
9832  {
9833  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
9834  }
9835  // else follow the continuations
9836  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
9837  {
9838  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9839  }
9840  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
9841  {
9842  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
9843  }
9844  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
9845  {
9846  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
9847  }
9848  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9849  Utilities->CallLogPop(1198);
9850  }
9851  catch(const Exception &e)
9852  {
9853  ErrorLog(160, e.Message);
9854  }
9855 }
9856 // ---------------------------------------------------------------------------
9857 
9858 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
9859 { // new at v2.4.0
9860  try
9861  {
9862  TrainController->LogEvent("JoinedByMenuItemClick");
9863  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
9864  TTrain *TrainToBeJoinedBy;
9866  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
9867  {
9868  if(TrainToBeJoinedBy->TrainMode != Signaller)
9869  {
9870  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
9871  Utilities->CallLogPop(2156);
9872  return;
9873  }
9874  // here if there is an adjacent train under signaller control
9875  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
9876  {
9877  ShowMessage("Can't join two trains when both are without power");
9878  Utilities->CallLogPop(2157);
9879  return;
9880  }
9881  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
9882  // set new values for mass etc
9883  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
9884  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
9885  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
9886  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
9887  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
9888  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
9889  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
9890 
9891  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
9892  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
9893  AnsiString LocName = "";
9894  if(ThisTrain.LeadElement > -1)
9895  {
9896  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
9897  }
9898  if((LocName == "") && (ThisTrain.MidElement > -1))
9899  {
9900  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
9901  }
9902  if((LocName == "") && ThisTrain.LeadElement > -1)
9903  {
9904  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
9905  }
9906  if((LocName == "") && (ThisTrain.MidElement > -1))
9907  {
9908  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
9909  }
9910  ThisTrain.StoppedWithoutPower = true;
9911  if(ThisTrain.PowerAtRail >= 1)
9912  {
9913  ThisTrain.StoppedWithoutPower = false;
9914  }
9915  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
9916  if(!ThisTrain.StoppedAtLocation)
9917  {
9918  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9920  }
9921  else
9922  {
9923  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9925  }
9926  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
9927  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
9928  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
9929  ThisTrain.ZeroPowerNoRearSplitMessage = false;
9930  ThisTrain.FailedTrainNoFinishJoinMessage = false;
9931  ThisTrain.ZeroPowerNoJoinedByMessage = false;
9932  ThisTrain.ZeroPowerNoCDTMessage = false;
9933  ThisTrain.ZeroPowerNoNewServiceMessage = false;
9935  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
9937  Utilities->CallLogPop(2158);
9938  }
9939  }
9940  catch(const Exception &e)
9941  {
9942  ErrorLog(207, e.Message);
9943  }
9944 }
9945 // ---------------------------------------------------------------------------
9946 
9947 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
9948 { // added at v2.4.0
9949  try
9950  {
9951  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
9952  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
9954  Train.TrainFailed = false;
9955  Train.StoppedWithoutPower = false;
9956  Train.SignallerStopped = true;
9957  if(!Train.StoppedAtLocation)
9958  {
9959  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9961  }
9962  else
9963  {
9964  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9966  }
9967  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
9968  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
9969  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
9970  AnsiString LocName = "";
9971  if(Train.LeadElement > -1)
9972  {
9973  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
9974  }
9975  if((LocName == "") && (Train.MidElement > -1))
9976  {
9977  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
9978  }
9979  if((LocName == "") && Train.LeadElement > -1)
9980  {
9981  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
9982  }
9983  if((LocName == "") && (Train.MidElement > -1))
9984  {
9985  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
9986  }
9987  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
9988  Train.ZeroPowerNoFrontSplitMessage = false;
9989  Train.ZeroPowerNoRearSplitMessage = false;
9990  Train.FailedTrainNoFinishJoinMessage = false;
9991  Train.ZeroPowerNoJoinedByMessage = false;
9992  Train.ZeroPowerNoCDTMessage = false;
9993  Train.ZeroPowerNoNewServiceMessage = false;
9995  Train.ZeroPowerNoRepeatShuttleMessage = false;
9997  Utilities->CallLogPop(2159);
9998  }
9999  catch(const Exception &e)
10000  {
10001  ErrorLog(208, e.Message);
10002  }
10003 }
10004 
10005 // ---------------------------------------------------------------------------
10006 
10007 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
10008 {
10009  try
10010  {
10011  TrainController->LogEvent("SignallerControlStopMenuItemClick");
10012  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
10015  if(Train.LeadElement > -1)
10016  {
10017  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10018  {
10019  Train.SignallerStoppingFlag = true;
10020  Train.SignallerStopBrakeRate = 0;
10021  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10022  }
10023  else
10025  }
10026  else
10028  Utilities->CallLogPop(1553);
10029  }
10030  catch(const Exception &e)
10031  {
10032  ErrorLog(161, e.Message);
10033  }
10034 }
10035 
10036 // ---------------------------------------------------------------------------
10037 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
10038 {
10039  try
10040  {
10041  TrainController->LogEvent("PassRedSignalMenuItemClick");
10042  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
10044  Train.SignallerStoppingFlag = false;
10045  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
10046  if(NextElementPos < 0)
10047  {
10048  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
10049  }
10050  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
10051 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
10052  if(!Train.StoppedAtSignal)
10053  {
10054  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
10055  }
10056 */
10057  if(TrackElement.TrackType != SignalPost)
10058  {
10059  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
10060  }
10061  Train.SignallerStopped = false;
10062  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10063  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10064  // since no need to alert the user
10065  Train.StoppedAfterSPAD = false; // in case had been set
10066  Train.SPADFlag = false;
10067  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10069  Train.AllowedToPassRedSignal = true;
10070  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10071  Utilities->CallLogPop(1199);
10072  }
10073  catch(const Exception &e)
10074  {
10075  ErrorLog(162, e.Message);
10076  }
10077 }
10078 // ---------------------------------------------------------------------------
10079 
10080 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
10081 {
10082  try
10083  {
10084  TrainController->LogEvent("StepForwardMenuItemClick");
10085  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
10087  Train.SignallerStoppingFlag = false;
10088  Train.SignallerStopped = false;
10089  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10090  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10091  // since no need to alert the user
10092  Train.StoppedAfterSPAD = false; // in case had been set
10093  Train.SPADFlag = false;
10094  Train.StepForwardFlag = true;
10095  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
10096  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10098  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10099  int NextElementPos = -1;
10100 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
10101  int NextEntryPos = -1; // ---ditto---
10102  if(Train.LeadElement > -1) // ---ditto---
10103  { // ---ditto---
10104  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10105  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10106  } // ---ditto---
10107  if((NextElementPos > -1) && (NextEntryPos > -1))
10108  { // call this after StepForwardFlag set
10109  Train.EntrySpeed = 0;
10111  Train.FirstHalfMove = true;
10112  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
10113  }
10114  Utilities->CallLogPop(1800);
10115  }
10116  catch(const Exception &e)
10117  {
10118  ErrorLog(163, e.Message);
10119  }
10120 }
10121 
10122 // ---------------------------------------------------------------------------
10123 
10124 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
10125 {
10126  try
10127  {
10128  TrainController->LogEvent("RemoveTrainMenuItemClick");
10129  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
10131  if((!Train.Derailed) && (!Train.Crashed))
10132  {
10133  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10135  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
10136  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
10137  TrainController->BaseTime = TDateTime::CurrentDateTime();
10139  if(button == IDNO)
10140  {
10141  Utilities->CallLogPop(1801);
10142  return;
10143  }
10144  }
10145  Train.SignallerStoppingFlag = false;
10146  Train.TrainGone = true; // will be removed by TTrainController::Operate
10147  Train.SignallerRemoved = true;
10148  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
10149  AnsiString LocName = "";
10150  if(Train.LeadElement > -1)
10151  {
10152  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
10153  }
10154  if((LocName == "") && (Train.MidElement > -1))
10155  {
10156  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
10157  }
10158  if((LocName == "") && Train.LeadElement > -1)
10159  {
10160  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
10161  }
10162  if((LocName == "") && (Train.MidElement > -1))
10163  {
10164  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
10165  }
10166  TTrackElement *TrackElementPtr;
10167  int RouteNumber;
10168  TAllRoutes::TRouteType RouteType;
10169  if(Train.LeadElement > -1)
10170  {
10171  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
10172  // remove TrainIDs from track element, added at v2.4.0
10173  if(TrackElementPtr->TrackType == Bridge)
10174  {
10175  if(Train.LeadExitPos > 1)
10176  {
10177  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10178  }
10179  else
10180  {
10181  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10182  }
10183  }
10184  else
10185  {
10186  TrackElementPtr->TrainIDOnElement = -1;
10187  }
10188  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
10189  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10190  {
10191  TrackElementPtr->CallingOnSet = false;
10192  Track->PlotSignal(6, *TrackElementPtr, Display);
10193  }
10194 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
10195 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
10196  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
10197  if(RouteType == TAllRoutes::AutoSigsRoute)
10198  {
10201  }
10202 // end of addition
10203  }
10204  if(Train.MidElement > -1)
10205  {
10206  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
10207  // remove TrainIDs from track element, added at v2.4.0
10208  if(TrackElementPtr->TrackType == Bridge)
10209  {
10210  if(Train.MidExitPos > 1)
10211  {
10212  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10213  }
10214  else
10215  {
10216  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10217  }
10218  }
10219  else
10220  {
10221  TrackElementPtr->TrainIDOnElement = -1;
10222  }
10223  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10224  {
10225  TrackElementPtr->CallingOnSet = false;
10226  Track->PlotSignal(7, *TrackElementPtr, Display);
10227  }
10228 // [added at v1.3.0 as above]
10230  {
10231  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
10232  if(RouteType == TAllRoutes::AutoSigsRoute)
10233  {
10236  }
10237  }
10238 // end of addition
10239  }
10240  if(Train.LeadElement > -1)
10241  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
10242  {
10243  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10244  {
10245  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
10246  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10247  {
10248  TrackElementPtr->CallingOnSet = false;
10249  Track->PlotSignal(8, *TrackElementPtr, Display);
10250  }
10251  }
10252  }
10253  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10254  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
10255  {
10256  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
10257  } // entries, including Fer if present
10258  Utilities->CallLogPop(1200);
10259  }
10260  catch(const Exception &e)
10261  {
10262  ErrorLog(164, e.Message);
10263  }
10264 }
10265 
10266 // ---------------------------------------------------------------------------
10267 
10268 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
10269  // to terminate after error message given
10270 {
10271  ErrorMessage->Visible = false;
10272  ErrorMessageStoreImage->Visible = false;
10273  ErrorButton->Visible = false;
10274  Display->GetImage()->Visible = true;
10275  Application->Terminate();
10276 }
10277 
10278 // ---------------------------------------------------------------------------
10279 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
10280 {
10281  try
10282  {
10283  TrainController->LogEvent("PerformancePanelLabelStartDrag");
10284  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
10285  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
10286  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
10287  Utilities->CallLogPop(1202);
10288  }
10289  catch(const Exception &e)
10290  {
10291  ErrorLog(165, e.Message);
10292  }
10293 }
10294 // ---------------------------------------------------------------------------
10295 
10296 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
10297 {
10298  try
10299  {
10300  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
10302  {
10303  UnicodeString MessageStr =
10304  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
10305  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10306  if(button == IDNO)
10307  {
10308  Action = caNone; // prevents form & application from closing
10309  Utilities->CallLogPop(1712);
10310  return;
10311  }
10312  }
10314  {
10315  UnicodeString MessStr = "";
10317  {
10318  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
10319  }
10320  else if(FileChangedFlag)
10321  {
10322  MessStr = UnicodeString("The railway has changed, exit without saving?");
10323  }
10324  else
10325  {
10326  MessStr = UnicodeString("The timetable has changed, exit without saving?");
10327  }
10328  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
10329  if(button == IDNO)
10330  {
10331  Action = caNone; // prevents form & application from closing
10332  Utilities->CallLogPop(1133);
10333  return;
10334  }
10335  }
10336 
10337  if(Level1Mode == OperMode)
10338  {
10340  {
10341  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
10342  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10344  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10345  TrainController->BaseTime = TDateTime::CurrentDateTime();
10347  if(button == IDNO)
10348  {
10349  Action = caNone; // prevents form & application from closing
10350  Utilities->CallLogPop(969);
10351  return;
10352  }
10353  }
10355  Utilities->PerformanceFile.close();
10356  }
10357  if((TempTTFileName != "") && FileExists(TempTTFileName))
10358  {
10359  DeleteFile(TempTTFileName);
10360  }
10361  Utilities->CallLogPop(971);
10362  }
10363  catch(const Exception &e)
10364  {
10365  ErrorLog(166, e.Message);
10366  }
10367 }
10368 
10369 // ---------------------------------------------------------------------------
10370 
10371 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
10372 {
10373 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
10374 // drop event log as have too many spurious entries
10375  try
10376  {
10377  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
10378  {
10379  if(Key == '2')
10380  {
10381  if(CallLogTickerLabel->Visible)
10382  {
10383  CallLogTickerLabel->Visible = false;
10384  }
10385  else
10386  {
10387  CallLogTickerLabel->Visible = true;
10388  }
10389  }
10390  else if(Key == '3')
10391  {
10392  if(DevelopmentPanel->Visible)
10393  {
10394  DevelopmentPanel->Visible = false;
10395  }
10396  else
10397  {
10398  DevelopmentPanel->Visible = true;
10399  DevelopmentPanel->BringToFront();
10400  }
10401  }
10402  else if(Key == '4')
10403  {
10404  TestFunction();
10405  }
10406  else if(Key == '5')
10407  {
10408  TMsgDlgButtons Buttons;
10409  Buttons << mbYes << mbNo;
10410  if(MessageDlg("Do you wish to allow facing signals next to bridges? If so please be aware that routes cannot be truncated to these signals.", mtWarning, Buttons, 0) == mrYes)
10411  {
10413  }
10414  else
10415  {
10417  }
10418  }
10419  }
10420  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10421  {
10422  CtrlKey = true;
10423  }
10424  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10425  {
10426  ShiftKey = true;
10427  }
10428 
10429 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
10430 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
10431 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
10432 
10433 //at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
10434 //is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
10435 //won't work on first press and that is less likely to be used a second time on either side of the message
10436 
10437  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10438  {
10439  if(LastNonCtrlOrShiftKeyDown == Key) //same key still down rejected
10440  {
10441  return;
10442  }
10443  else
10444  {
10446  }
10447  }
10448 
10449  if(Key == VK_UP)
10450  {
10451  if(ScreenUpButton->Enabled)
10452  ScreenUpButton->Click();
10453  }
10454  else if(Key == VK_DOWN)
10455  {
10456  if(ScreenDownButton->Enabled)
10457  ScreenDownButton->Click();
10458  }
10459  else if(Key == VK_LEFT)
10460  {
10461  if(ScreenLeftButton->Enabled)
10462  ScreenLeftButton->Click();
10463  }
10464  else if(Key == VK_RIGHT)
10465  {
10466  if(ScreenRightButton->Enabled)
10467  ScreenRightButton->Click();
10468  }
10469  else if(Key == VK_HOME)
10470  {
10471  if(HomeButton->Enabled)
10472  HomeButton->Click();
10473  }
10474 // end of 1.3.0 addition
10475  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10476  {
10477  if(ZoomButton->Enabled)
10478  ZoomButton->Click();
10479  }
10480  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10481  {
10482  if(ZoomButton->Enabled)
10483  ZoomButton->Click();
10484  }
10485 
10486 //below added for v2.4.2 to add more keyboard shortcuts
10487  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() || SpeedEditBox2->Focused()
10488  || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() || SpeedEditBox->Focused()
10489  || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
10490  {// prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
10491  return;
10492  }
10493 
10494  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
10495  {
10496  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h'))//TimetablePanel uses Shift H too so disable this when it's in use
10497  {
10498  NewHomeButton->Click();
10499  }
10500  }
10501 
10502 //Operating panel
10503  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10504  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10505  if(!Shift.Contains(ssCtrl))
10506  {
10507  if(OperateButton->Visible && OperateButton->Enabled)
10508  {
10509  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
10510  {
10511  OperateButton->Click();
10512  }
10513  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
10514  {
10515  OperateButton->Click();
10516  }
10517  }
10518  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
10519  {
10520  PresetAutoSigRoutesButton->Click();
10521  }
10522  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
10523  {
10524  PerformanceLogButton->Click();
10525  }
10526  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
10527  {
10528  CallingOnButton->Click();
10529  }
10530  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
10531  {
10532  OperatorActionButton->Click();
10533  }
10534  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
10535  {
10536  RouteCancelButton->Click();
10537  }
10538  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
10539  {
10540  TTClockAdjButton->Click();
10541  }
10542  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') //route buttons - autosigs
10543  {
10544  AutoSigsButton->Click();
10545  }
10546  if(SigPrefButton->Visible && SigPrefButton->Enabled && Key == '2') //route buttons - prefdir
10547  {
10548  SigPrefButton->Click();
10549  }
10550  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') //route buttons - unrestricted
10551  {
10552  UnrestrictedButton->Click();
10553  }
10554  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
10555  {
10556  ExitOperationButton->Click();
10557  }
10558  }
10559  else //CtrlKey down
10560  {
10561  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
10562  {
10563  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10564  if(Key == 'S' || Key == 's')//so this will never execute
10565  {
10566  SaveSessionButton->Click();
10567  }
10568  }
10569  }
10570  }
10571 
10572 //Timetable clock adjust panel
10573  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10574  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10575  if(Shift.Contains(ssShift))
10576  {
10577  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
10578  {
10579  TTClockExitButton->Click();
10580  }
10581  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
10582  {
10583  TTClockResetButton->Click();
10584  }
10585  }
10586  }
10587 
10588 //Track build panel
10589  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
10590  {
10591  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10592  {
10593  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) //add/remove track elements
10594  {
10595  AddTrackButton->Click();
10596  }
10597  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) //cycle through signal aspects
10598  {
10599  SigAspectButton->Click();
10600  }
10601  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) //link track
10602  {
10603  TrackOKButton->Click();
10604  }
10605  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) //change font
10606  {
10607  FontButton->Click();
10608  }
10609  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) //name locations
10610  {
10611  LocationNameButton->Click();
10612  }
10613  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) //set distances/speeds
10614  {
10615  SetLengthsButton->Click();
10616  }
10617  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) //add text
10618  {
10619  AddTextButton->Click();
10620  }
10621  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) //toggle grid
10622  {
10623  ScreenGridButton->Click();
10624  }
10625  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) //move text or graphic
10626  {
10627  MoveTextOrGraphicButton->Click();
10628  }
10629  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) //insert image
10630  {
10631  UserGraphicButton->Click();
10632  }
10633  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) //join gaps
10634  {
10635  SetGapsButton->Click();
10636  }
10637  }
10638  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10639  {
10640  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) //save railway in trackbuild mode
10641  {
10642  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10643  if(Key == 'S' || Key == 's')//so this will never execute
10644  {
10645  SaveRailwayTBPButton->Click();
10646  }
10647  }
10648  }
10649  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10650  {
10651  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') //escape key
10652  {
10653  ExitTrackButton->Click();
10654  }
10655  }
10656  }
10657 
10658 //PrefDir panel
10659  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
10660  {
10661  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10662  {
10663  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') //escape key
10664  {
10665  ExitPrefDirButton->Click();
10666  }
10667  }
10668  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
10669  {
10670  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
10671  {
10672  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10673  if(Key == 'S' || Key == 's')//so this will never execute
10674  {
10675  SaveRailwayPDPButton->Click();
10676  }
10677  }
10678  }
10679  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10680  {
10681  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) //add pref dir
10682  {
10683  AddPrefDirButton->Click();
10684  }
10685  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) //delete one pref dir
10686  {
10687  DeleteOnePrefDirButton->Click();
10688  }
10689  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) //delete all pref dirs
10690  {
10691  DeleteAllPrefDirButton->Click();
10692  }
10693  }
10694  }
10695 //Note that save button in BaseMode is handled by Ctrl S from the File menu
10696 
10697 //Timetable panel
10698  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
10699  {
10700  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10701  {
10702  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') //escape key
10703  {
10704  ExitTTModeButton->Click();
10705  }
10706  }
10707  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) //show/hide timetable edit panel
10708  {
10709  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
10710  {
10711  if(!TimetableEditPanel->Visible)
10712  {
10713  if(Key == 'S' || Key == 's')
10714  {
10715  ShowHideTTButton->Click();
10716  }
10717  }
10718  else if(Key == 'H' || Key == 'h')
10719  {
10720  ShowHideTTButton->Click();
10721  }
10722  }
10723  }
10724  }
10725 
10726 //Timetable edit panel
10727 //These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
10728 //is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
10729 //showing. See DevHistory.txt for the version after v2.4.3 for details.
10730  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
10731  {
10732  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10733  {
10734  AllEntriesTTListBoxTopPosition = AllEntriesTTListBox->TopIndex; //store value here before the Windows key press function runs (it runs after any local code)
10735  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
10736  {
10737  PreviousTTEntryKeyFlag = true;
10738  }
10739  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
10740  {
10741  NextTTEntryKeyFlag = true;
10742  }
10743  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
10744  {
10745  MoveTTEntryUpKeyFlag = true;
10746  }
10747  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
10748  {
10749  MoveTTEntryDownKeyFlag = true;
10750  }
10751  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
10752  {
10753  CopyTTEntryKeyFlag = true;
10754  }
10755  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
10756  {
10757  CutTTEntryKeyFlag = true;
10758  }
10759  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
10760  {
10761  PasteTTEntryKeyFlag = true;
10762  }
10763  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
10764  {
10765  DeleteTTEntryKeyFlag = true;
10766  }
10767 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
10768  {
10769  SaveTTEntryKeyFlag = true;
10770  }
10771  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
10772  {
10773  CancelTTActionKeyFlag = true;
10774  }
10775 */
10776  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
10777  {
10778  NewTTEntryKeyFlag = true;
10779  }
10780  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
10781  {
10782  AZOrderKeyFlag = true;
10783  }
10784 /*
10785  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
10786  {
10787  AddMinsKeyFlag = true;
10788  }
10789  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
10790  {
10791  SubMinsKeyFlag = true;
10792  }
10793 */
10794  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
10795  {
10797  }
10798  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
10799  {
10800  ValidateTimetableKeyFlag = true;
10801  }
10802  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
10803  {
10804  SaveTTKeyFlag = true;
10805  }
10806  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
10807  {
10808  SaveTTAsKeyFlag = true;
10809  }
10810  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
10811  {
10812  RestoreTTKeyFlag = true;
10813  }
10814  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
10815  {
10816  ExportTTKeyFlag = true;
10817  }
10818  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
10819  {
10820  ConflictAnalysisKeyFlag = true;
10821  }
10822  }
10823  }
10824 
10825 
10826 //Information menu
10827  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
10828  {
10829  if(Key == 'I' || Key == 'i') //toggle track info
10830  {
10831  TrackInfoOnOffMenuItem->Click();
10832  }
10833  else if(TrainInfoMenuItem->Enabled)
10834  {
10835  if(Key == 'S' || Key == 's') //toggle train status info
10836  {
10838  }
10839  else if(Key == 'T' || Key == 't') //toggle train timetable info
10840  {
10841  TrainTTInfoOnOffMenuItem->Click();
10842  }
10843 
10844  }
10845  }
10846 //end of 2.4.2 addition
10847 
10848  }
10849  catch(const Exception &e)
10850  {
10851  ErrorLog(167, e.Message);
10852  }
10853 }
10854 
10855 // ---------------------------------------------------------------------------
10856 
10857 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
10858 {
10859  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10860  LastNonCtrlOrShiftKeyDown = -1; //reset value to no key down
10861  CtrlKey = false;
10862  ShiftKey = false;
10863  SaveMenuItem->ShortCut = 16467; //restore Ctrl S for save menu in case set to 0 in FormKeyDown
10864 }
10865 
10866 // ---------------------------------------------------------------------------
10867 
10868 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10869 {
10870  if((Button == mbRight) && Level2OperMode == Operating)
10871  {
10872  OutputLog1->Caption = "";
10873  }
10874 }
10875 
10876 // ---------------------------------------------------------------------------
10877 
10878 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10879 {
10880  if((Button == mbRight) && Level2OperMode == Operating)
10881  {
10882  OutputLog2->Caption = "";
10883  }
10884 }
10885 // ---------------------------------------------------------------------------
10886 
10887 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10888 {
10889  if((Button == mbRight) && Level2OperMode == Operating)
10890  {
10891  OutputLog3->Caption = "";
10892  }
10893 }
10894 
10895 // ---------------------------------------------------------------------------
10896 
10897 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10898 {
10899  if((Button == mbRight) && Level2OperMode == Operating)
10900  {
10901  OutputLog4->Caption = "";
10902  }
10903 }
10904 
10905 // ---------------------------------------------------------------------------
10906 
10907 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10908 {
10909  if((Button == mbRight) && Level2OperMode == Operating)
10910  {
10911  OutputLog5->Caption = "";
10912  }
10913 }
10914 // ---------------------------------------------------------------------------
10915 
10916 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10917 {
10918  if((Button == mbRight) && Level2OperMode == Operating)
10919  {
10920  OutputLog6->Caption = "";
10921  }
10922 }
10923 
10924 // ---------------------------------------------------------------------------
10925 
10926 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10927 {
10928  if((Button == mbRight) && Level2OperMode == Operating)
10929  {
10930  OutputLog7->Caption = "";
10931  }
10932 }
10933 
10934 // ---------------------------------------------------------------------------
10935 
10936 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10937 {
10938  if((Button == mbRight) && Level2OperMode == Operating)
10939  {
10940  OutputLog8->Caption = "";
10941  }
10942 }
10943 
10944 // ---------------------------------------------------------------------------
10945 
10946 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10947 {
10948  if((Button == mbRight) && Level2OperMode == Operating)
10949  {
10950  OutputLog9->Caption = "";
10951  }
10952 }
10953 
10954 // ---------------------------------------------------------------------------
10955 
10956 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10957 {
10958  if((Button == mbRight) && Level2OperMode == Operating)
10959  {
10960  OutputLog10->Caption = "";
10961  }
10962 }
10963 
10964 // ---------------------------------------------------------------------------
10965 
10966 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
10967 {
10968  try
10969  {
10970  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
10971  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
10972  {
10974  SetLevel2OperMode(3);
10975  MasterClock->Enabled = false;
10976  }
10977  AboutForm->ShowModal();
10978  }
10979  catch(const Exception &e)
10980  {
10981  ErrorLog(168, e.Message);
10982  }
10983 }
10984 
10985 // ---------------------------------------------------------------------------
10986 
10987 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
10988 {
10989  try
10990  {
10991  // Helpfile allocated during construction of Interface
10992  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
10993  }
10994  catch(const Exception &e)
10995  {
10996  ErrorLog(175, e.Message);
10997  }
10998 }
10999 
11000 // ---------------------------------------------------------------------------
11001 
11002 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
11003 {
11004  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
11005  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
11006 }
11007 
11008 // ---------------------------------------------------------------------------
11009 
11010 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
11011 {
11012  try
11013  {
11014  TrainController->LogEvent("BlackBgndMenuItemClick");
11015  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
11016  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
11017  if(ColFile.fail())
11018  {
11019  // ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
11020  // no need for message as will revert to black by default
11021  }
11022  else
11023  {
11024  Utilities->SaveFileString(ColFile, "black");
11025  ColFile.close(); // added at v2.3.0, should have been in earlier
11026  }
11027  TColor OldTransparentColour = Utilities->clTransparent;
11028  Utilities->clTransparent = TColor(0);
11029  SelectBitmap->TransparentColor = Utilities->clTransparent;
11031  TextBox->Color = clB3G3R3;
11033 
11034  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11035  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11036  Level1Mode = BaseMode;
11037  SetLevel1Mode(128);
11038  Utilities->CallLogPop(1797);
11039  }
11040  catch(const Exception &e)
11041  {
11042  ErrorLog(170, e.Message);
11043  }
11044 }
11045 
11046 // ---------------------------------------------------------------------------
11047 
11048 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
11049 {
11050  try
11051  {
11052  TrainController->LogEvent("WhiteBgndMenuItemClick");
11053  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
11054  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
11055  if(ColFile.fail())
11056  {
11057  ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
11058  }
11059  else
11060  {
11061  Utilities->SaveFileString(ColFile, "white");
11062  ColFile.close(); // added at v2.3.0, should have been in earlier
11063  }
11064  TColor OldTransparentColour = Utilities->clTransparent;
11065  Utilities->clTransparent = TColor(0xFFFFFF);
11066  SelectBitmap->TransparentColor = Utilities->clTransparent;
11068  TextBox->Color = clB5G5R5;
11070 
11071  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11072  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11073  Level1Mode = BaseMode;
11074  SetLevel1Mode(129);
11075  Utilities->CallLogPop(1798);
11076  }
11077  catch(const Exception &e)
11078  {
11079  ErrorLog(171, e.Message);
11080  }
11081 }
11082 
11083 // ---------------------------------------------------------------------------
11084 
11085 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
11086 {
11087  try
11088  {
11089  TrainController->LogEvent("BlueBgndMenuItemClick");
11090  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
11091  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
11092  if(ColFile.fail())
11093  {
11094  ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
11095  }
11096  else
11097  {
11098  Utilities->SaveFileString(ColFile, "blue");
11099  ColFile.close(); // added at v2.3.0, should have been in earlier
11100  }
11101  TColor OldTransparentColour = Utilities->clTransparent;
11102  Utilities->clTransparent = TColor(0x330000);
11103  SelectBitmap->TransparentColor = Utilities->clTransparent;
11105  TextBox->Color = clB3G3R3;
11107 
11108  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11109  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11110  Level1Mode = BaseMode;
11111  SetLevel1Mode(130);
11112  Utilities->CallLogPop(1799);
11113  }
11114  catch(const Exception &e)
11115  {
11116  ErrorLog(172, e.Message);
11117  }
11118 }
11119 
11120 // ---------------------------------------------------------------------------
11121 
11122 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
11123 {
11124  if(SpeedTopLabel->Caption == "mph")
11125  {
11126  SpeedTopLabel->Caption = "km/h";
11127  SpeedBottomLabel->Caption = "mph";
11128  }
11129  else
11130  {
11131  SpeedTopLabel->Caption = "mph";
11132  SpeedBottomLabel->Caption = "km/h";
11133  }
11134  // swap values to match toggle state
11135  UnicodeString SavedTopValue = SpeedEditBox->Text;
11136  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
11137 
11138  SpeedEditBox->Text = SavedBottomValue;
11139  SpeedVariableLabel->Caption = SavedTopValue;
11140 }
11141 // ---------------------------------------------------------------------------
11142 
11143 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
11144 {
11145  if(SpeedTopLabel2->Caption == "mph")
11146  {
11147  SpeedTopLabel2->Caption = "km/h";
11148  SpeedBottomLabel2->Caption = "mph";
11149  }
11150  else
11151  {
11152  SpeedTopLabel2->Caption = "mph";
11153  SpeedBottomLabel2->Caption = "km/h";
11154  }
11155  // swap values to match toggle state
11156  UnicodeString SavedTopValue = SpeedEditBox2->Text;
11157  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
11158 
11159  SpeedEditBox2->Text = SavedBottomValue;
11160  SpeedVariableLabel2->Caption = SavedTopValue;
11161 }
11162 // ---------------------------------------------------------------------------
11163 
11164 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11165 {
11166  try
11167  {
11168  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
11169  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
11170  bool ErrorFlag = false, TooBigFlag = false;
11171  if(SpeedEditBox->Text.Length() > 0)
11172  {
11173  if(SpeedEditBox->Text.Length() > 5)
11174  {
11175  TooBigFlag = true;
11176  }
11177  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
11178  {
11179  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
11180  {
11181  SpeedVariableLabel->Caption = "Entry error";
11182  ErrorFlag = true;
11183  break;
11184  }
11185  if(TooBigFlag)
11186  {
11187  SpeedVariableLabel->Caption = "Too big";
11188  break;
11189  }
11190  }
11191  if(!ErrorFlag && !TooBigFlag)
11192  {
11193 /*
11194  1 mph = 1.609344 km/h
11195  1 km/h = 0.621371 mph
11196 */
11197  if(SpeedTopLabel->Caption == "mph")
11198  {
11199  // do mph-to-km/h conversion
11200  int MPH = SpeedEditBox->Text.ToInt();
11201  int KPH = (MPH * 1.609344) + 0.5;
11202  SpeedVariableLabel->Caption = UnicodeString(KPH);
11203  }
11204  else
11205  {
11206  // do km/h-to-mph conversion
11207  int KPH = SpeedEditBox->Text.ToInt();
11208  int MPH = (KPH * 0.621371) + 0.5;
11209  SpeedVariableLabel->Caption = UnicodeString(MPH);
11210  }
11211  }
11212  }
11213  else
11214  {
11215  SpeedVariableLabel->Caption = "";
11216  }
11217  Utilities->CallLogPop(1865);
11218  }
11219  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11220  {
11221  SpeedVariableLabel->Caption = "Entry error";
11222  }
11223  catch(const Exception &e)
11224  {
11225  ErrorLog(176, e.Message);
11226  }
11227 }
11228 
11229 // ---------------------------------------------------------------------------
11230 
11231 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
11232 {
11233  if(PowerTopLabel->Caption == "HP")
11234  {
11235  PowerTopLabel->Caption = "kW";
11236  PowerBottomLabel->Caption = "HP";
11237  }
11238  else
11239  {
11240  PowerTopLabel->Caption = "HP";
11241  PowerBottomLabel->Caption = "kW";
11242  }
11243  // swap values to match toggle state
11244  UnicodeString SavedTopValue = PowerEditBox->Text;
11245  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
11246 
11247  PowerEditBox->Text = SavedBottomValue;
11248  PowerVariableLabel->Caption = SavedTopValue;
11249 }
11250 // ---------------------------------------------------------------------------
11251 
11252 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11253 {
11254  try
11255  {
11256  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
11257  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
11258  bool ErrorFlag = false, TooBigFlag = false;
11259  if(PowerEditBox->Text.Length() > 0)
11260  {
11261  if(PowerEditBox->Text.Length() > 8)
11262  {
11263  TooBigFlag = true;
11264  }
11265  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
11266  {
11267  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
11268  {
11269  PowerVariableLabel->Caption = "Entry error";
11270  ErrorFlag = true;
11271  break;
11272  }
11273  if(TooBigFlag)
11274  {
11275  PowerVariableLabel->Caption = "Too big";
11276  break;
11277  }
11278  }
11279  if(!ErrorFlag && !TooBigFlag)
11280  {
11281 /*
11282  1 kW = 1.340482574 HP
11283  1 HP = 0.745699872 kW
11284 */
11285  if(PowerTopLabel->Caption == "HP")
11286  {
11287  // do HP-to-kW conv
11288  int HP = PowerEditBox->Text.ToInt();
11289  int KW = (HP * 0.745699872) + 0.5;
11290  PowerVariableLabel->Caption = UnicodeString(KW);
11291  }
11292  else
11293  {
11294  // do kW-to-HP conv
11295  int KW = PowerEditBox->Text.ToInt();
11296  int HP = (KW * 1.340482574) + 0.5;
11297  PowerVariableLabel->Caption = UnicodeString(HP);
11298  }
11299  }
11300  }
11301  else
11302  {
11303  PowerVariableLabel->Caption = "";
11304  }
11305  Utilities->CallLogPop(1868);
11306  }
11307  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11308  {
11309  PowerVariableLabel->Caption = "Entry error";
11310  }
11311  catch(const Exception &e)
11312  {
11313  ErrorLog(179, e.Message);
11314  }
11315 }
11316 // ---------------------------------------------------------------------------
11317 
11318 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11319 {
11320  try
11321  {
11322  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
11323  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
11324  bool ErrorFlag = false, TooBigFlag = false;
11325  if(SpeedEditBox2->Text.Length() > 0)
11326  {
11327  if(SpeedEditBox2->Text.Length() > 5)
11328  {
11329  TooBigFlag = true;
11330  }
11331  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
11332  {
11333  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
11334  {
11335  SpeedVariableLabel2->Caption = "Entry error";
11336  ErrorFlag = true;
11337  break;
11338  }
11339  if(TooBigFlag)
11340  {
11341  SpeedVariableLabel2->Caption = "Too big";
11342  break;
11343  }
11344  }
11345  if(!ErrorFlag && !TooBigFlag)
11346  {
11347 /*
11348  1 mph = 1.609344 km/h
11349  1 km/h = 0.621371 mph
11350 */
11351  if(SpeedTopLabel2->Caption == "mph")
11352  {
11353  // do mph-to-km/h conversion
11354  int MPH = SpeedEditBox2->Text.ToInt();
11355  int KPH = (MPH * 1.609344) + 0.5;
11356  SpeedVariableLabel2->Caption = AnsiString(KPH);
11357  }
11358  else
11359  {
11360  // do km/h-to-mph conversion
11361  int KPH = SpeedEditBox2->Text.ToInt();
11362  int MPH = (KPH * 0.621371) + 0.5;
11363  SpeedVariableLabel2->Caption = AnsiString(MPH);
11364  }
11365  }
11366  }
11367  else
11368  {
11369  SpeedVariableLabel2->Caption = "";
11370  }
11371  Utilities->CallLogPop(1866);
11372  }
11373  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11374  {
11375  SpeedVariableLabel2->Caption = "Entry error";
11376  }
11377  catch(const Exception &e)
11378  {
11379  ErrorLog(177, e.Message);
11380  }
11381 }
11382 
11383 // ---------------------------------------------------------------------------
11384 
11385 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11386 {
11387  try
11388  {
11389  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
11390  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
11391  bool ErrorFlag = false, TooLongFlag = false;
11392  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
11393  {
11394  for(int x = 1; x <= MileEdit->Text.Length(); x++)
11395  {
11396  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
11397  {
11398  MetreVariableLabel->Caption = "Entry error";
11399  ErrorFlag = true;
11400  break;
11401  }
11402  }
11403  }
11404  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
11405  {
11406  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
11407  {
11408  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
11409  {
11410  MetreVariableLabel->Caption = "Entry error";
11411  ErrorFlag = true;
11412  break;
11413  }
11414  }
11415  }
11416  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
11417  {
11418  for(int x = 1; x <= YardEdit->Text.Length(); x++)
11419  {
11420  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
11421  {
11422  MetreVariableLabel->Caption = "Entry error";
11423  ErrorFlag = true;
11424  break;
11425  }
11426  }
11427  }
11428  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
11429  {
11430  TooLongFlag = true;
11431  MetreVariableLabel->Caption = "Too big";
11432  }
11433  if(!ErrorFlag && !TooLongFlag)
11434  {
11435  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
11436  if(MileEdit->Text.Length() > 0)
11437  {
11438  Miles = MileEdit->Text.ToInt();
11439  }
11440  if(ChainEdit->Text.Length() > 0)
11441  {
11442  Chains = ChainEdit->Text.ToInt();
11443  }
11444  if(YardEdit->Text.Length() > 0)
11445  {
11446  Yards = YardEdit->Text.ToInt();
11447  }
11448  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
11449  MetreVariableLabel->Caption = AnsiString(Metres);
11450  }
11451  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
11452  {
11453  MetreVariableLabel->Caption = "";
11454  }
11455  Utilities->CallLogPop(1867);
11456  }
11457  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11458  {
11459  MetreVariableLabel->Caption = "Entry error";
11460  }
11461  catch(const Exception &e)
11462  {
11463  ErrorLog(178, e.Message);
11464  }
11465 }
11466 
11467 // ---------------------------------------------------------------------------
11468 
11469 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
11470 {
11471  try
11472  {
11473  TrainController->LogEvent("TTClockAdjButtonClick");
11474  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
11475 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
11476  Display->HideWarningLog(0); //because this panel overwrites it
11477  TTClockAdjPanel->Visible = true;
11478  TTClockAdjButton->Enabled = false;
11479 /*
11480  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
11481  OperatingPanel->Enabled = false;
11482  ZoomButton->Enabled = false;
11483  HomeButton->Enabled = false;
11484  NewHomeButton->Enabled = false;
11485  ScreenLeftButton->Enabled = false;
11486  ScreenRightButton->Enabled = false;
11487  ScreenUpButton->Enabled = false;
11488  ScreenDownButton->Enabled = false;
11489 */
11490  Utilities->CallLogPop(1875);
11491  }
11492  catch(const Exception &e)
11493  {
11494  ErrorLog(181, e.Message);
11495  }
11496 }
11497 
11498 // ---------------------------------------------------------------------------
11499 
11500 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
11501 {
11502  try
11503  {
11504  TrainController->LogEvent("TTClockExitButtonClick");
11505  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
11506  TTClockAdjPanel->Visible = false;
11507  TTClockAdjButton->Enabled = true;
11508 /* these dealt with in ClockTimer2
11509  ZoomButton->Enabled = true;
11510  HomeButton->Enabled = true;
11511  NewHomeButton->Enabled = true;
11512  ScreenLeftButton->Enabled = true;
11513  ScreenRightButton->Enabled = true;
11514  ScreenUpButton->Enabled = true;
11515  ScreenDownButton->Enabled = true;
11516  OperatingPanel->Enabled = true;
11517  OperatingPanelLabel->Caption = "Operation";
11518 */
11519  Display->ShowWarningLog(0);
11520  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
11521  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
11522  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
11524  {
11525  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height)/2);
11526  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width)/2);
11527  TTClockAdjustWarningLabel->Caption =
11528  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
11529  TTClockAdjustWarningPanel->Visible = true;
11530  }
11531 // Utilities->Clock2Stopped = false; // as above
11532  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
11533  Utilities->CallLogPop(1876);
11534  }
11535  catch(const Exception &e)
11536  {
11537  ErrorLog(182, e.Message);
11538  }
11539 }
11540 // ---------------------------------------------------------------------------
11541 
11542 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
11543 {
11544  try
11545  {
11546  TrainController->LogEvent("TTClockx2ButtonClick");
11547  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
11548  TTClockSpeed = 2;
11549  TTClockSpeedLabel->Caption = "x2";
11551  Utilities->CallLogPop(1878);
11552  }
11553  catch(const Exception &e)
11554  {
11555  ErrorLog(184, e.Message);
11556  }
11557 }
11558 
11559 // ---------------------------------------------------------------------------
11560 
11561 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
11562 {
11563  try
11564  {
11565  TrainController->LogEvent("TTClockx4ButtonClick");
11566  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
11567  TTClockSpeed = 4;
11568  TTClockSpeedLabel->Caption = "x4";
11570  Utilities->CallLogPop(1883);
11571  }
11572  catch(const Exception &e)
11573  {
11574  ErrorLog(189, e.Message);
11575  }
11576 }
11577 
11578 // ---------------------------------------------------------------------------
11579 
11580 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
11581 {
11582  try
11583  {
11584  TrainController->LogEvent("TTClockx8ButtonClick");
11585  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
11586  TTClockSpeed = 8;
11587  TTClockSpeedLabel->Caption = "x8";
11589  Utilities->CallLogPop(1884);
11590  }
11591  catch(const Exception &e)
11592  {
11593  ErrorLog(190, e.Message);
11594  }
11595 }
11596 
11597 // ---------------------------------------------------------------------------
11598 
11599 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
11600 {
11601  try
11602  {
11603  TrainController->LogEvent("TTClockx16ButtonClick");
11604  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
11605  TTClockSpeed = 16;
11606  TTClockSpeedLabel->Caption = "x16";
11608  Utilities->CallLogPop(1885);
11609  }
11610  catch(const Exception &e)
11611  {
11612  ErrorLog(191, e.Message);
11613  }
11614 }
11615 
11616 // ---------------------------------------------------------------------------
11617 
11618 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
11619 {
11620  try
11621  {
11622  TrainController->LogEvent("TTClockx1ButtonClick");
11623  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
11624  TTClockSpeed = 1;
11625  TTClockSpeedLabel->Caption = "x1";
11627  Utilities->CallLogPop(1886);
11628  }
11629  catch(const Exception &e)
11630  {
11631  ErrorLog(192, e.Message);
11632  }
11633 }
11634 
11635 // ---------------------------------------------------------------------------
11636 
11637 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
11638 {
11639  try
11640  {
11641  TrainController->LogEvent("TTClockxHalfButtonClick");
11642  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
11643  TTClockSpeed = 0.5;
11644  TTClockSpeedLabel->Caption = "x1/2";
11646  Utilities->CallLogPop(1887);
11647  }
11648  catch(const Exception &e)
11649  {
11650  ErrorLog(193, e.Message);
11651  }
11652 }
11653 
11654 // ---------------------------------------------------------------------------
11655 
11656 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
11657 {
11658  try
11659  {
11660  TrainController->LogEvent("TTClockxQuarterButtonClick");
11661  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
11662  TTClockSpeed = 0.25;
11663  TTClockSpeedLabel->Caption = "x1/4";
11665  Utilities->CallLogPop(1888);
11666  }
11667  catch(const Exception &e)
11668  {
11669  ErrorLog(194, e.Message);
11670  }
11671 }
11672 
11673 // ---------------------------------------------------------------------------
11674 
11675 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
11676 { // added for v2.3.0 for very big railways
11677  try
11678  {
11679  TrainController->LogEvent("TTClockxEighthButtonClick");
11680  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
11681  TTClockSpeed = 0.125;
11682  TTClockSpeedLabel->Caption = "x1/8";
11684  Utilities->CallLogPop(2099);
11685  }
11686  catch(const Exception &e)
11687  {
11688  ErrorLog(203, e.Message);
11689  }
11690 }
11691 // ---------------------------------------------------------------------------
11692 
11693 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
11694 { // added for v2.3.0 for very big railways
11695  try
11696  {
11697  TrainController->LogEvent("TTClockxSixteenthButtonClick");
11698  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
11699  TTClockSpeed = 0.0625;
11700  TTClockSpeedLabel->Caption = "x1/16";
11702  Utilities->CallLogPop(2100);
11703  }
11704  catch(const Exception &e)
11705  {
11706  ErrorLog(204, e.Message);
11707  }
11708 }
11709 
11710 // ---------------------------------------------------------------------------
11711 
11712 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
11713 {
11714  try
11715  {
11716  TrainController->LogEvent("TTClockAdd1hButtonClick");
11717  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
11718  double TTClockIncrement = 1.0 / 24;
11719  TrainController->RestartTime += TDateTime(TTClockIncrement);
11722  Utilities->CallLogPop(1879);
11723  }
11724  catch(const Exception &e)
11725  {
11726  ErrorLog(185, e.Message);
11727  }
11728 }
11729 
11730 // ---------------------------------------------------------------------------
11731 
11732 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
11733 {
11734  try
11735  {
11736  TrainController->LogEvent("TTClockAdd10mButtonClick");
11737  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
11738  double TTClockIncrement = 1.0 / 144;
11739  TrainController->RestartTime += TDateTime(TTClockIncrement);
11742  Utilities->CallLogPop(1881);
11743  }
11744  catch(const Exception &e)
11745  {
11746  ErrorLog(187, e.Message);
11747  }
11748 }
11749 
11750 // ---------------------------------------------------------------------------
11751 
11752 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
11753 {
11754  try
11755  {
11756  TrainController->LogEvent("TTClockAdd1mButtonClick");
11757  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
11758  double TTClockIncrement = 1.0 / 1440;
11759  TrainController->RestartTime += TDateTime(TTClockIncrement);
11762  Utilities->CallLogPop(1882);
11763  }
11764  catch(const Exception &e)
11765  {
11766  ErrorLog(188, e.Message);
11767  }
11768 }
11769 
11770 // ---------------------------------------------------------------------------
11771 
11772 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
11773 {
11774  try
11775  {
11776  TrainController->LogEvent("TTClockResetButtonClick");
11777  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
11782  if(TTClockSpeed == 2)
11783  TTClockSpeedLabel->Caption = "x2";
11784  else if(TTClockSpeed == 4)
11785  TTClockSpeedLabel->Caption = "x4";
11786  else if(TTClockSpeed == 8)
11787  TTClockSpeedLabel->Caption = "x8";
11788  else if(TTClockSpeed == 16)
11789  TTClockSpeedLabel->Caption = "x16";
11790  else if(TTClockSpeed == 0.5)
11791  TTClockSpeedLabel->Caption = "x1/2";
11792  else if(TTClockSpeed == 0.25)
11793  TTClockSpeedLabel->Caption = "x1/4";
11794  else if(TTClockSpeed == 0.125)
11795  TTClockSpeedLabel->Caption = "x1/8";
11796  else if(TTClockSpeed == 0.0625)
11797  TTClockSpeedLabel->Caption = "x1/16";
11798  else
11799  {
11800  TTClockSpeed = 1;
11801  TTClockSpeedLabel->Caption = "x1";
11802  }
11803  Utilities->CallLogPop(1880);
11804  }
11805  catch(const Exception &e)
11806  {
11807  ErrorLog(186, e.Message);
11808  }
11809 }
11810 
11811 // ---------------------------------------------------------------------------
11812 
11813 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
11814 {
11815  try
11816  {
11817  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
11818  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
11819  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
11820  OperatingPanelLabel->Caption = "Disabled";
11821  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
11822  ZoomButton->Enabled = false;
11823  HomeButton->Enabled = false;
11824  NewHomeButton->Enabled = false;
11825  ScreenLeftButton->Enabled = false;
11826  ScreenRightButton->Enabled = false;
11827  ScreenUpButton->Enabled = false;
11828  ScreenDownButton->Enabled = false;
11829 
11830  Screen->Cursor = TCursor(-11); // Hourglass
11831  TPrefDirElement StartElement, EndElement;
11832  bool PointsChanged, AtLeastOneSet = false;
11833  int LastIteratorValue = 0;
11834  while(true)
11835  {
11836  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
11837  break;
11838  // rest of routine here - i.e. build the routes
11839  ConstructRoute->ClearRoute(); // in case not empty though should be
11840  AtLeastOneSet = true;
11841  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true, true))
11842  // true for both ConsecSignalsRoute & AutoSigsFlag
11843  {}
11844  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
11845  PointsChanged))
11846  {}
11848  }
11849  if(AtLeastOneSet)
11850  {
11853  }
11854  else
11855  {
11856  ShowMessage("No presettable automatic signal routes are available");
11857  }
11858  Screen->Cursor = TCursor(-2); // Arrow
11859  Utilities->CallLogPop(1994);
11860  }
11861  catch(const Exception &e)
11862  {
11863  ErrorLog(195, e.Message);
11864  }
11865 }
11866 
11867 // ---------------------------------------------------------------------------
11868 
11869 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
11870 {
11871  try
11872  {
11873  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
11874  { // else fails on shutdown because HiddenScreen & other things no longer exist
11875  int DispW = (Interface->Width - 64 - 16) / 16;
11876 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
11877  int DispH = (Interface->Height - 192) / 16;
11878  MainScreen->Width = DispW * 16;
11879  MainScreen->Height = DispH * 16;
11880  Utilities->ScreenElementWidth = DispW;
11881  Utilities->ScreenElementHeight = DispH;
11882  HiddenScreen->Width = MainScreen->Width;
11883  HiddenScreen->Height = MainScreen->Height;
11884  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
11885  PerformancePanel->Left = MainScreen->Left;
11886  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
11887  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
11888  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
11889  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
11890  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
11891  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
11892  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
11893  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
11894  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
11895  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
11896 
11897  if(!Display->ZoomOutFlag)
11898  {
11900  }
11901  else
11902  {
11903  Display->ClearDisplay(11);
11905  }
11906  Display->Update();
11907  }
11908  }
11909  catch(const Exception &e)
11910  {
11911  ErrorLog(197, e.Message);
11912  }
11913 }
11914 
11915 // ---------------------------------------------------------------------------
11916 
11917 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
11918 {
11919  try
11920  {
11921  TrainController->LogEvent("OperatorActionButtonClick");
11922  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
11924  {
11925  ShowOperatorActionPanel = true;
11926  OperatorActionPanel->Visible = true;
11928  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
11929  }
11930  else
11931  {
11932  ShowOperatorActionPanel = false;
11933  OperatorActionPanel->Visible = false;
11935  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
11936  }
11937  Utilities->CallLogPop(2073);
11938  }
11939  catch(const Exception &e)
11940  {
11941  ErrorLog(199, e.Message);
11942  }
11943 }
11944 
11945 // ---------------------------------------------------------------------------
11946 
11948 {
11949  try
11950  {
11951  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
11952  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
11954  if(Utilities->RHSignalFlag) // RH sigs after conversion
11955  {
11956  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
11958  {
11960  }
11961  else
11962  {
11964  }
11965  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
11966  SigsOnLeftImage1->Visible = false;
11967  SigsOnLeftImage2->Visible = false;
11968  SigsOnRightImage1->Visible = true;
11969  SigsOnRightImage2->Visible = true;
11970  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
11971  if(SigFile.fail())
11972  {
11973  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
11974  }
11975  else
11976  {
11977  Utilities->SaveFileString(SigFile, "RHSignals");
11978  }
11979  }
11980  else // LH sigs after conversion
11981  {
11982  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
11984  {
11986  }
11987  else
11988  {
11990  }
11991  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
11992  SigsOnRightImage1->Visible = false;
11993  SigsOnRightImage2->Visible = false;
11994  SigsOnLeftImage1->Visible = true;
11995  SigsOnLeftImage2->Visible = true;
11996  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
11997  if(SigFile.fail())
11998  {
11999  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
12000  }
12001  else
12002  {
12003  Utilities->SaveFileString(SigFile, "LHSignals");
12004  }
12005  }
12006  Utilities->CallLogPop(2097);
12007  }
12008  catch(const Exception &e)
12009  {
12010  ErrorLog(202, e.Message);
12011  }
12012 }
12013 // ---------------------------------------------------------------------------
12014 
12015 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12016 
12017 {
12018  try
12019  {
12020  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
12021  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
12022  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12023  {
12024  Utilities->CallLogPop(2160);
12025  return;
12026  }
12027  bool TooBigFlag = false, BadCharsFlag = false;
12030  if(MTBFEditBox->Text.Length() > 0)
12031  {
12032  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
12033  {
12034  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
12035  {
12036  BadCharsFlag = true;
12037  break;
12038  }
12039  }
12040  if(!BadCharsFlag)
12041  {
12042  if(StrToInt(MTBFEditBox->Text) > 10000)
12043  {
12044  TooBigFlag = true;
12045  }
12046  }
12047  if(TooBigFlag)
12048  {
12049  ShowMessage("Maximum value allowed is 10,000");
12050  MTBFEditBox->Text = "";
12053  Utilities->CallLogPop(2161);
12054  return;
12055  }
12056  if(BadCharsFlag)
12057  {
12058  ShowMessage("Value must be a whole number with no special characters");
12059  MTBFEditBox->Text = "";
12062  Utilities->CallLogPop(2162);
12063  return;
12064  }
12065  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
12067  }
12069  {
12070  MTBFEditBox->Text = "";
12072  }
12073  Utilities->CallLogPop(2163);
12074  }
12075  catch(const Exception &e)
12076  {
12077  ErrorLog(209, e.Message);
12078  }
12079 }
12080 
12081 // ---------------------------------------------------------------------------
12082 
12083 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
12084 {
12085  try
12086  {
12087  TrainController->LogEvent("MTBFEditBoxClick");
12088  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12089  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12090  {
12091  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
12093  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
12094  }
12095  Utilities->CallLogPop(2164);
12096  }
12097  catch(const Exception &e)
12098  {
12099  ErrorLog(210, e.Message);
12100  }
12101 }
12102 
12103 // ---------------------------------------------------------------------------
12104 
12105 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
12106 {
12107  try
12108  {
12109  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12110  LengthConversionPanel->Visible = false;
12111  SpeedConversionPanel->Visible = false;
12112  DistanceKey->Visible = false;
12113  TrackElementPanel->Visible = false;
12114  SigAspectButton->Enabled = false;
12116  SetLevel2TrackMode(63);
12117  Display->Update();
12118  if(SelectedGraphicFileName != "")
12119  {
12120  UserGraphicReselectPanel->Visible = true;
12121  }
12122  else
12123  {
12124  UserGraphicReselectPanel->Visible = false;
12125  LoadUserGraphic(0);
12126  }
12127  Utilities->CallLogPop(2183);
12128  }
12129  catch(const Exception &e)
12130  {
12131  ErrorLog(212, e.Message);
12132  }
12133 }
12134 
12135 // ---------------------------------------------------------------------------
12136 
12137 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
12138 {
12139  try
12140  {
12141  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
12142  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
12143  UserGraphicReselectPanel->Visible = false;
12144  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
12145  if(UGMIt == Track->UserGraphicMap.end())
12146  {
12147  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
12148  Utilities->CallLogPop(2196);
12149  return;
12150  }
12152  SetLevel2TrackMode(64);
12153  Utilities->CallLogPop(2184);
12154  }
12155  catch(const Exception &e)
12156  {
12157  ErrorLog(213, e.Message);
12158  }
12159 }
12160 // ---------------------------------------------------------------------------
12161 
12162 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
12163 {
12164  try
12165  {
12166  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
12167  UserGraphicReselectPanel->Visible = false;
12168  LoadUserGraphic(1);
12169  Utilities->CallLogPop(2185);
12170  }
12171  catch(const Exception &e)
12172  {
12173  ErrorLog(214, e.Message);
12174  }
12175 }
12176 
12177 // ---------------------------------------------------------------------------
12178 
12179 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
12180 {
12181  try
12182  {
12183  TrainController->LogEvent("TTClockAdjustOKButtonClick");
12184  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
12185  TTClockAdjustWarningPanel->Visible = false;
12186  if(TTClockAdjustCheckBox->Checked)
12187  {
12188  TTClockAdjustWarningHide = true;
12189  }
12190  Utilities->CallLogPop(2219);
12191  }
12192  catch(const Exception &e)
12193  {
12194  ErrorLog(216, e.Message);
12195  }
12196 }
12197 
12198 //---------------------------------------------------------------------------
12199 
12200 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
12201 {
12202  try
12203  {
12204  TrainController->LogEvent("ConflictAnalysisButtonClick");
12205  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
12206  ConflictPanel->Visible = true;
12207  Utilities->CallLogPop(2220);
12208  }
12209  catch(const Exception &e)
12210  {
12211  ErrorLog(217, e.Message);
12212  }
12213 }
12214 
12215 //---------------------------------------------------------------------------
12216 
12217 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
12218 {
12219  try
12220  {
12221  TrainController->LogEvent("CPCancelButtonClick");
12222  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
12223  ConflictPanel->Visible = false;
12224  Utilities->CallLogPop(2221);
12225  }
12226  catch(const Exception &e)
12227  {
12228  ErrorLog(218, e.Message);
12229  }
12230 }
12231 
12232 //---------------------------------------------------------------------------
12233 
12234 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
12235 {
12236  try
12237  {
12238  TrainController->LogEvent("CPGenFileButtonClick");
12239  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
12240  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked)
12241  {
12242  ShowMessage("No boxes ticked!");
12243  }
12244  else //keep ticks & range values from last time, only reset on startup
12245  {
12246  Screen->Cursor = TCursor(-11);//hourglass
12247  AnsiString TTTitle;
12249  {
12250  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
12251  {
12252  if(CreateEditTTFileName[x] == '\\')
12253  {
12254  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
12255  break;
12256  }
12257  }
12259  CPAtLocCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
12260  {
12261  ShowMessage("Analysis complete and file created");
12262  }
12263  ConflictPanel->Visible = false;
12264  }
12265  }
12266  Screen->Cursor = TCursor(-2);//arrow
12267  Utilities->CallLogPop(2222);
12268  }
12269  catch(const Exception &e)
12270  {
12271  ErrorLog(219, e.Message);
12272  }
12273 }
12274 
12275 //---------------------------------------------------------------------------
12276 // end of fastcalls & directly associated functions
12277 // ---------------------------------------------------------------------------
12278 
12279 void TInterface::SetTopIndex(int Caller)
12280 {
12281 //Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
12282  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
12283  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
12284  {
12286  }
12287  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
12288  {
12289  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
12290  }
12291  else
12292  {
12293  AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex;
12294  }
12295  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
12296  Utilities->CallLogPop(2207);
12297 }
12298 
12299 // ---------------------------------------------------------------------------
12300 
12301 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
12302 {
12303  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
12304  bool ClockState = Utilities->Clock2Stopped;
12305 
12306  Utilities->Clock2Stopped = true;
12308  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
12309  if(ScreenGridFlag && (Level1Mode == TrackMode))
12310  {
12311  int WidthNum = int(MainScreen->Width / 160) + 1;
12312  int HeightNum = int(MainScreen->Height / 144) + 1;
12313  for(int x = 0; x < WidthNum; x++)
12314  {
12315  for(int y = 0; y < HeightNum; y++)
12316  {
12317  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
12318  }
12319  }
12320  }
12321 
12322 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
12323 // elements but before active elements. This is so text can overwite stations and non-station named locations.
12324 
12326 
12327 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
12328 // used to occur frequently without Disp->Update() in PlotOriginal
12329 
12330  // OperMode LCs plotted below
12332  {
12334  }
12335 
12336  if(Level1Mode == PrefDirMode)
12337  {
12338  if(EveryPrefDir->PrefDirSize() > 0)
12339  {
12341  }
12343  {
12345  }
12346  }
12347 
12348  if(Level1Mode == TrackMode)
12349  {
12351  {
12352  LocationNameButton->Enabled = true;
12353  }
12354  else
12355  {
12356  LocationNameButton->Enabled = false;
12357  }
12358  }
12359 
12361  {
12363  DistanceKey->Visible = true;
12364  DistancesMarked = true;
12365  LengthConversionPanel->Visible = true;
12366  SpeedConversionPanel->Visible = true;
12367  }
12368 
12369  if(Level2TrackMode == DistanceContinuing) // for extended distances
12370  {
12371  if(ConstructPrefDir->PrefDirSize() > 0)
12372  {
12373  Track->LengthMarker(2, HiddenDisplay); //this line was after the next line until v2.5.1, changed so magenta not overrridden after PrefDirMarker called
12375  DistanceKey->Visible = true;
12376  DistancesMarked = true;
12377  LengthConversionPanel->Visible = true;
12378  SpeedConversionPanel->Visible = true;
12379  }
12380  }
12381 
12383  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
12384  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
12385  {
12387  DistanceKey->Visible = true;
12388  }
12389 
12391  // cancel DistancesMarked if exit from any of these modes
12392  {
12393  DistancesMarked = false;
12394  DistanceKey->Visible = false;
12395  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12396  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12397  }
12398 
12400  // in process of moving so use NewSelectBitmapHLoc & VLoc
12401  {
12403  }
12404 
12406  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
12407  {
12409  }
12410 
12411  if(Level1Mode == OperMode)
12412  {
12414  if(!AllRoutes->LockedRouteVector.empty())
12415  {
12416  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
12417  {
12418  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
12419  {
12420  AllRoutes->LockedRouteVector.erase(LRVIT);
12421  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
12422  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
12423  // route being on the other track of a 2-track element doesn't arise)
12424  continue;
12425  }
12426  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
12427  int x = Route.PrefDirSize() - 1;
12428  bool BreakFlag = false;
12429  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
12430  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
12431  {
12432  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12433  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12434  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
12435  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
12436  {
12437  BreakFlag = true;
12438  break; // train removed earlier element from route so stop here
12439  }
12440  x--;
12441  if(x < 0) //added after Albie Vowles reported error on 14/08/20 by email
12442  { //it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
12443  BreakFlag = true; //at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
12444  break; //it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
12445  }
12446  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
12447  }
12448  if(!BreakFlag)
12449  {
12450  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
12451  {
12452  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12453  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12454  }
12455  }
12456  }
12457  }
12458 
12459  if(RouteMode == RouteContinuing)
12460  {
12462 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
12465  if(AutoSigsFlag)
12467  else if(ConsecSignalsRoute)
12469  else
12471  }
12472 
12473  if(Track->PointFlashFlag)
12474  {
12475  // need to reset the screen location for picking up the original graphic
12476  int Left, Top; // Embarcadero change - these missing in error from Borland file
12478  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
12479  PointFlash->SetSourceRect(Left, Top);
12480  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
12481  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
12482  }
12483 
12484  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
12485  // In order to avoid plotting the whole LC for every element of a LC a TempMarker is used
12486  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12487  {
12488  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->TempMarker = false;
12489  }
12490  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12491  {
12492  int BaseSpeedTag;
12493  TTrackElement ATE;
12494  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
12495  {
12496  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
12497  if(ITE.TempMarker == false)
12498  {
12499  if(ITE.Attribute == 0)
12500  {
12502  }
12503  else if(ITE.Attribute == 1)
12504  {
12506  }
12507  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting
12508  // won't set marker but no real time lost in this case
12509  }
12510  }}
12512  }
12513 
12514  Display->ZoomOutFlag = false;
12515  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
12516  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
12517  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
12518  Utilities->Clock2Stopped = ClockState;
12519  Utilities->CallLogPop(91);
12520 }
12521 
12522 // ---------------------------------------------------------------------------
12523 
12524 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
12525 {
12526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
12527  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
12528  {
12529  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
12530  {
12531  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
12532  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
12535  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
12536  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
12539  }
12540  InfoPanel->Visible = true;
12541  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
12542  ClearandRebuildRailway(31); // get rid of earlier gap selection
12543  Utilities->CallLogPop(92);
12544  return true; // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
12545  }
12546  Utilities->CallLogPop(93);
12547  return false; // no unset ones left to find
12548 }
12549 
12550 // ---------------------------------------------------------------------------
12551 
12553 {
12554  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
12555  if(FileChangedFlag)
12556  {
12557  UnicodeString MessageStr = "The railway has changed, close it without saving?";
12558  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12559  if(button == IDNO)
12560  {
12561  Utilities->CallLogPop(1140);
12562  return false;
12563  }
12564  }
12565  Display->ClearDisplay(7);
12567 
12568  Display->DisplayOffsetH = 0;
12569  Display->DisplayOffsetV = 0;
12574 
12575 // these ensure that all persistent vectors, maps & multimaps etc are cleared
12576  delete TrainController;
12577  delete EveryPrefDir;
12578  delete ConstructRoute;
12579  delete ConstructPrefDir;
12580  delete AllRoutes;
12581  delete Track;
12582  delete TextHandler;
12583 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
12584 // pop earlier pushed values
12585 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
12586 // railway
12587  TextHandler = new TTextHandler;
12588  Track = new TTrack;
12589  AllRoutes = new TAllRoutes;
12591  ConstructRoute = new TOneRoute;
12592  EveryPrefDir = new TOnePrefDir;
12594  PerformanceLogBox->Lines->Clear();
12595  ResetAll(1);
12596  Utilities->CallLogPop(94);
12597  return true;
12598 }
12599 
12600 // ---------------------------------------------------------------------------
12601 
12602 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
12603 {
12604  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
12605  std::ifstream VecFile(FileName);
12606 
12607  if(VecFile.is_open())
12608  {
12609  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
12610  {
12611  VecFile.close();
12612  Utilities->CallLogPop(1805);
12613  return false;
12614  }
12615  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
12616  {
12617  VecFile.close();
12618  Utilities->CallLogPop(1440);
12619  return false;
12620  }
12621  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
12622  {
12623  VecFile.close();
12624  Utilities->CallLogPop(1441);
12625  return false;
12626  }
12627  bool GraphicsFollow = false;
12628  int NumberOfActiveElements;
12629  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
12630  {
12631  VecFile.close();
12632  Utilities->CallLogPop(95);
12633  return false;
12634  }
12635  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
12636  {
12637  VecFile.close();
12638  Utilities->CallLogPop(96);
12639  return false;
12640  }
12641  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
12642  {
12643  VecFile.close();
12644  Utilities->CallLogPop(97);
12645  return false;
12646  }
12647  if(GraphicsFollow)
12648  {
12649  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
12650  {
12651  VecFile.close();
12652  Utilities->CallLogPop(2186);
12653  return false;
12654  }
12655  }
12656  VecFile.close();
12657  }
12658  else
12659  {
12660  Utilities->CallLogPop(1153);
12661  return false;
12662  }
12663  Utilities->CallLogPop(98);
12664  return true;
12665 }
12666 
12667 // ---------------------------------------------------------------------------
12668 
12669 void TInterface::Delay(int Caller, double Msec)
12670 {
12671  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
12672  TDateTime First, Second;
12673  bool Finished = false;
12674 
12675  First = TDateTime::CurrentDateTime();
12676  double TimeVal1 = 86400000 * double(First); // no of msec in a day
12677 
12678  while(!Finished)
12679  {
12680  Second = TDateTime::CurrentDateTime();
12681  double TimeVal2 = 86400000 * double(Second);
12682  if((TimeVal2 - TimeVal1) > Msec)
12683  Finished = true;
12684  }
12685  Utilities->CallLogPop(1203);
12686 }
12687 
12688 // ---------------------------------------------------------------------------
12689 
12691 {
12692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
12693  if(CurrentSpeedButton)
12694  CurrentSpeedButton->Down = false;
12695  CurrentSpeedButton = 0;
12696  Utilities->CallLogPop(1204);
12697 }
12698 
12699 // ---------------------------------------------------------------------------
12700 
12702 {
12703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
12704  int TrainID;
12705 
12706  if(ConstructRoute->SearchVectorSize() == 0)
12707  {
12708  Utilities->CallLogPop(99);
12709  return false;
12710  }
12711  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
12712  {
12713  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
12714  if(PrefDirElement.TrackType == Bridge)
12715  {
12716  if(PrefDirElement.GetXLinkPos() < 2)
12717  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
12718  else
12719  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
12720  }
12721  else
12722  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
12723  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
12724  {
12725  Utilities->CallLogPop(100);
12726  return true;
12727  }
12728  // check for crossed diagonal fouling by train added at v1.2.0
12729  int TrainID; // not used
12730  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
12731  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
12732  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
12733  {
12734  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
12735  {
12736  Utilities->CallLogPop(2037);
12737  return true;
12738  }
12739  }
12740  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
12741  {
12742  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
12743  {
12744  Utilities->CallLogPop(2038);
12745  return true;
12746  }
12747  }
12748  }
12749  Utilities->CallLogPop(101);
12750  return false;
12751 }
12752 
12753 // ---------------------------------------------------------------------------
12754 
12756 {
12757  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
12758  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
12759  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
12760  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
12761  RouteCancelFlag = false;
12763  {
12764  RouteCancelButton->Enabled = true;
12765  }
12766  else
12767  {
12768  RouteCancelButton->Enabled = false;
12769  }
12772 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
12773  InfoPanel->Visible = true;
12774  if(Level2OperMode != Paused)
12775  {
12776  InfoPanel->Caption = InfoCaptionStore;
12777  }
12778  Utilities->CallLogPop(102);
12779 }
12780 
12781 // ---------------------------------------------------------------------------
12782 
12783 // usermode functions below
12785 {
12786  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
12787  if(!Display->ZoomOutFlag)
12788  {
12791  Track->GapFlashFlag = false;
12792  }
12793 // GapFlash resets when any mode selected unless zoomed out
12794 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
12795 // reset GapFlashFlag
12796  switch(Level1Mode) // use the data member
12797  {
12798  case BaseMode:
12799  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
12800  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
12801  PasteMenuItem->ShortCut = TextToShortCut("");
12806  LengthConversionPanel->Visible = false;
12807  SpeedConversionPanel->Visible = false;
12808  TimetableEditPanel->Visible = false;
12809  TrackBuildPanel->Visible = false;
12810  TrackElementPanel->Visible = false;
12811  LocationNameTextBox->Visible = false;
12812  TextBox->Visible = false;
12813  TrackLengthPanel->Visible = false;
12814  InfoPanel->Visible = false;
12815  PrefDirPanel->Visible = false;
12816  TimetablePanel->Visible = false;
12817  OperatingPanel->Visible = false;
12818  PrefDirKey->Visible = false;
12819  TrackLinkedImage->Visible = false;
12820  TrackNotLinkedImage->Visible = false;
12821  GapsSetImage->Visible = false;
12822  GapsNotSetImage->Visible = false;
12823  LocationNamesSetImage->Visible = false;
12824  LocationNamesNotSetImage->Visible = false;
12825  ModeMenu->Enabled = true;
12826  FileMenu->Enabled = true;
12827  EditMenu->Enabled = false;
12828  BuildTrackMenuItem->Enabled = true;
12829  SigAspectButton->Enabled = false;
12830  Track->ChangingLCVector.clear();
12831  Track->BarriersDownVector.clear();
12833  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
12834  SigImagePanel->Visible = false; // new at v2.3.0
12835  MTBFEditBox->Visible = false; // new at v2.4.0
12836  MTBFLabel->Visible = false;
12837  TTClockAdjustWarningPanel->Visible = false;
12838  if(Track->IsTrackFinished())
12839  {
12840  PlanPrefDirsMenuItem->Enabled = true;
12841  if(TimetableTitle != "")
12842  {
12843  OperateRailwayMenuItem->Enabled = true;
12844  }
12845  else
12846  {
12847  OperateRailwayMenuItem->Enabled = false;
12848  }
12849  }
12850  else
12851  {
12852  PlanPrefDirsMenuItem->Enabled = false;
12853  OperateRailwayMenuItem->Enabled = false;
12854  }
12855  if(RlyFile)
12856  {
12857  LoadTimetableMenuItem->Enabled = true;
12858  }
12859  else
12860  {
12861  LoadTimetableMenuItem->Enabled = false;
12862  }
12863  LoadRailwayMenuItem->Enabled = true;
12864  if(NoRailway())
12865  {
12866  SaveAsMenuItem->Enabled = false;
12867  ImageMenu->Enabled = false;
12868  SaveImageAndGridMenuItem->Enabled = false;
12869  SaveImageNoGridMenuItem->Enabled = false;
12870  SaveImageAndPrefDirsMenuItem->Enabled = false;
12871  SaveOperatingImageMenuItem->Enabled = false;
12872  BlackBgndMenuItem->Enabled = false;
12873  WhiteBgndMenuItem->Enabled = false;
12874  BlueBgndMenuItem->Enabled = false;
12875  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
12876  SigImagePanel->Visible = true; // new at v2.3.0
12877  if(Utilities->clTransparent != TColor(0))
12878  {
12879  BlackBgndMenuItem->Enabled = true;
12880  }
12881  if(Utilities->clTransparent != TColor(0xFFFFFF))
12882  {
12883  WhiteBgndMenuItem->Enabled = true;
12884  }
12885  if(Utilities->clTransparent != TColor(0x330000))
12886  {
12887  BlueBgndMenuItem->Enabled = true;
12888  }
12889  ClearAllMenuItem->Enabled = false;
12890  InfoPanel->Visible = true;
12891  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
12892  }
12893  else
12894  {
12895  InfoPanel->Visible = false;
12896  SaveAsMenuItem->Enabled = true;
12897  ImageMenu->Enabled = true;
12898  SaveImageAndGridMenuItem->Enabled = true;
12899  SaveImageNoGridMenuItem->Enabled = true;
12900  if(EveryPrefDir->PrefDirSize() > 0)
12901  SaveImageAndPrefDirsMenuItem->Enabled = true;
12902  else
12903  SaveImageAndPrefDirsMenuItem->Enabled = false;
12904  BlackBgndMenuItem->Enabled = false;
12905  WhiteBgndMenuItem->Enabled = false;
12906  BlueBgndMenuItem->Enabled = false;
12907  SaveOperatingImageMenuItem->Enabled = false;
12908  ClearAllMenuItem->Enabled = true;
12909  }
12910  if(SavedFileName == "")
12911  {
12912  SaveMenuItem->Enabled = false;
12913  }
12914  else if(!FileChangedFlag)
12915  {
12916  SaveMenuItem->Enabled = false;
12917  }
12918  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
12919  {
12920  if(!(Track->IsReadyForOperation()))
12921  {
12922  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
12923  }
12924  else
12925  {
12926  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
12927  }
12928  }
12929  else
12930  SaveMenuItem->Enabled = true;
12931  LoadSessionMenuItem->Enabled = true;
12932  ExitMenuItem->Enabled = true;
12933  ScreenGridFlag = false;
12934  TrainController->CrashWarning = false;
12935  TrainController->DerailWarning = false;
12936  TrainController->SPADWarning = false;
12938  TrainController->CallOnWarning = false;
12941  UserGraphicReselectPanel->Visible = false;
12942  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
12943  SetTrackBuildImages(13);
12944  break;
12945 
12946  case TimetableMode:
12950  ModeMenu->Enabled = false;
12951  SigImagePanel->Visible = false; // new at v2.3.0
12952  FileMenu->Enabled = false;
12953  EditMenu->Enabled = false;
12954  FloatingInfoMenu->Enabled = false;
12955  ImageMenu->Enabled = false;
12956  TimetableEditPanel->BringToFront();
12957  TimetableHandler();
12958  break;
12959 
12960  case TrackMode:
12961  if(Level2TrackMode == CutMoving)
12962  {
12963  Level2TrackMode = Pasting; // paste the selection
12964  SetLevel2TrackMode(52);
12965  }
12970  TrackBuildPanel->Visible = true;
12971  TrackBuildPanelLabel->Caption = "Build/modify";
12972  TrackElementPanel->Visible = false;
12973  TrackLengthPanel->Visible = false;
12974  PrefDirPanel->Visible = false;
12975  TimetablePanel->Visible = false;
12976  OperatingPanel->Visible = false;
12977  InfoPanel->Visible = false;
12978  InfoPanel->Caption = "";
12979  LocationNameTextBox->Visible = false;
12980  TextBox->Visible = false;
12981  ModeMenu->Enabled = false;
12982  SigImagePanel->Visible = false; // new at v2.3.0
12983  FileMenu->Enabled = false;
12984  // set edit menu items
12986  // track buttons
12987  AddTrackButton->Enabled = true;
12989  {
12990  LocationNameButton->Enabled = true;
12991  }
12992  else
12993  {
12994  LocationNameButton->Enabled = false;
12995  }
12996  ScreenGridButton->Enabled = true;
12997  ExitTrackButton->Enabled = true;
12998  SetGapsButton->Enabled = false;
12999  TrackOKButton->Enabled = false;
13000  if(Track->GapsUnset(5))
13001  {
13002  SetGapsButton->Enabled = true;
13003  }
13004  // only enable if there are gaps still to be set (returns false for no track)
13005  else
13006  {
13007  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
13008  {
13009  TrackOKButton->Enabled = true;
13010  }
13011  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
13012  }
13013  SetLengthsButton->Enabled = false;
13014  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
13015  {
13016  SetLengthsButton->Enabled = true;
13017  }
13018  // text buttons
13019  AddTextButton->Enabled = true;
13020  TextOrUserGraphicGridButton->Enabled = true;
13021  FontButton->Enabled = true;
13022  MoveTextOrGraphicButton->Enabled = false;
13023  if(TextHandler->TextVectorSize(9) > 0)
13024  {
13025  MoveTextOrGraphicButton->Enabled = true;
13026  }
13027  if(!Track->UserGraphicVector.empty())
13028  {
13029  MoveTextOrGraphicButton->Enabled = true;
13030  }
13031  SelectionValid = false;
13033  TimetableTitle = "";
13034  SetCaption(0);
13035  break;
13036 
13037  case PrefDirMode:
13041  PrefDirPanel->Visible = true;
13042  PrefDirPanelLabel->Caption = "Preferred direction selection";
13043 
13044  InfoPanel->Visible = true;
13045  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
13046  PrefDirKey->Visible = true;
13047  ModeMenu->Enabled = false;
13048  SigImagePanel->Visible = false; // new at v2.3.0
13049  FileMenu->Enabled = false;
13050 // set edit menu items
13052  AddPrefDirButton->Enabled = false;
13053  DeleteOnePrefDirButton->Enabled = false;
13055  if(EveryPrefDir->PrefDirSize() > 0)
13056  {
13057  DeleteAllPrefDirButton->Visible = true;
13058  DeleteAllPrefDirButton->Enabled = true;
13059  SaveImageAndPrefDirsMenuItem->Enabled = true;
13060  }
13061  else
13062  {
13063  DeleteAllPrefDirButton->Enabled = false;
13064  SaveImageAndPrefDirsMenuItem->Enabled = false;
13065  }
13066  ExitPrefDirButton->Enabled = true;
13067  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
13068 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
13069 // SetCaption();
13070  break;
13071 
13072  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
13076  OperatingPanel->Visible = true;
13077  OperatingPanelLabel->Caption = "Operation";
13078 
13079  CallingOnButton->Visible = false;
13080  PresetAutoSigRoutesButton->Visible = true;
13081  PresetAutoSigRoutesButton->Enabled = true;
13082  InfoPanel->Visible = true;
13083  SigImagePanel->Visible = false; // new at v2.3.0
13084  ModeMenu->Enabled = false;
13085  FileMenu->Enabled = false;
13086  EditMenu->Enabled = false;
13087  ImageMenu->Enabled = true;
13088  SaveImageAndGridMenuItem->Enabled = true;
13089  SaveImageNoGridMenuItem->Enabled = true;
13090  if(EveryPrefDir->PrefDirSize() > 0)
13091  SaveImageAndPrefDirsMenuItem->Enabled = true;
13092  else
13093  SaveImageAndPrefDirsMenuItem->Enabled = false;
13094  SaveOperatingImageMenuItem->Enabled = true;
13095  AutoSigsFlag = false;
13096  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
13098  {
13099  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13100  }
13101  else
13102  {
13103  MTBFEditBox->Text = "";
13104  }
13105  MTBFEditBox->ReadOnly = false; // because this is prestart mode
13106  MTBFLabel->Visible = true;
13107  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13109  if(EveryPrefDir->PrefDirSize() > 0)
13110  {
13111  ConsecSignalsRoute = true;
13112  PreferredRoute = true;
13113  }
13114  else // no PrefDirs
13115  {
13116  ConsecSignalsRoute = false;
13117  PreferredRoute = false;
13118  }
13119 
13120  OperateButton->Enabled = true;
13121  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13122  ExitOperationButton->Enabled = true;
13123  TTClockAdjButton->Enabled = true;
13124  ShowPerformancePanel = false;
13125  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
13126  ShowOperatorActionPanel = false; // new at v2.2.0
13127  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
13128 
13130 
13131  Utilities->Clock2Stopped = false;
13135  TTClockSpeed = 1;
13136  TTClockSpeedLabel->Caption = "x1";
13139 
13140  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
13141  // format "16/06/2009 20:55:17"
13142  // avoid characters in filename:= / \ : * ? " < > |
13143  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
13144 
13145  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
13146  if(Utilities->PerformanceFile.fail())
13147  {
13148  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
13149  " in the folder where the 'Railway.exe' program file resides");
13150  }
13152 // DisableRouteButtons(2); enable route setting or pre-start
13153 // DisablePanelsStoreMainMenuStates();
13154  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
13155  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
13156 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
13157 
13158 // reset all performance indicators
13182 
13183  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
13184  OAListBox->Clear();
13185  OAListBox->Items->Add(L""); // hints for OpActionPanel
13186  OAListBox->Items->Add(L"");
13187  OAListBox->Items->Add(L"");
13188  OAListBox->Items->Add(L"Left click");
13189  OAListBox->Items->Add(L"headcode");
13190  OAListBox->Items->Add(L"to locate train");
13191  OAListBox->Items->Add(L"");
13192  OAListBox->Items->Add(L"");
13193  OAListBox->Items->Add(L"");
13194  OAListBox->Items->Add(L"");
13195  OAListBox->Items->Add(L"Left click and");
13196  OAListBox->Items->Add(L"hold grey area");
13197  OAListBox->Items->Add(L"to move panel");
13198 
13199  ClearandRebuildRailway(55); // so points display with one fillet
13200  break;
13201 
13202  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
13203  Level1Mode = OperMode;
13204 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
13207  OperatingPanel->Visible = true;
13208  OperatingPanelLabel->Caption = "Operation";
13209 
13210  CallingOnButton->Visible = true;
13211  PresetAutoSigRoutesButton->Visible = false;
13212  InfoPanel->Visible = true;
13213  ModeMenu->Enabled = false;
13214  SigImagePanel->Visible = false; // new at v2.3.0
13215  FileMenu->Enabled = false;
13216  EditMenu->Enabled = false;
13217  ImageMenu->Enabled = true;
13218  SaveImageAndGridMenuItem->Enabled = true;
13219  SaveImageNoGridMenuItem->Enabled = true;
13220  if(EveryPrefDir->PrefDirSize() > 0)
13221  SaveImageAndPrefDirsMenuItem->Enabled = true;
13222  else
13223  SaveImageAndPrefDirsMenuItem->Enabled = false;
13224  SaveOperatingImageMenuItem->Enabled = true;
13225 
13226  OperateButton->Enabled = true;
13227  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13228  ExitOperationButton->Enabled = true;
13229  TTClockAdjButton->Enabled = true;
13232  if(Level2OperMode == Paused)
13233  DisableRouteButtons(3); // could be PreStart or Paused
13238  TTClockSpeed = 1;
13239  TTClockSpeedLabel->Caption = "x1";
13241  ShowPerformancePanel = false; // added at v2.2.0
13242  ShowOperatorActionPanel = false; // new at v2.2.0
13243  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
13244  OAListBox->Clear();
13245  OAListBox->Items->Add(L""); // hints for OpActionPanel
13246  OAListBox->Items->Add(L"");
13247  OAListBox->Items->Add(L"");
13248  OAListBox->Items->Add(L"Left click");
13249  OAListBox->Items->Add(L"headcode");
13250  OAListBox->Items->Add(L"to locate train");
13251  OAListBox->Items->Add(L"");
13252  OAListBox->Items->Add(L"");
13253  OAListBox->Items->Add(L"");
13254  OAListBox->Items->Add(L"");
13255  OAListBox->Items->Add(L"Left click and");
13256  OAListBox->Items->Add(L"hold grey area");
13257  OAListBox->Items->Add(L"to move panel");
13258  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
13259  {
13260  MTBFEditBox->Visible = true;
13262  {
13263  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13264  }
13265  else
13266  {
13267  MTBFEditBox->Text = "";
13268  }
13269  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
13270  MTBFLabel->Visible = true;
13271  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13273  }
13274  else
13275  {
13276  MTBFEditBox->Visible = false;
13277  MTBFEditBox->Text = "";
13278  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
13279  MTBFLabel->Visible = false;
13280  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13282  }
13283  break;
13284 
13285  default:
13286  // No further recursion in BaseMode so OK
13287  Level1Mode = BaseMode;
13288  SetLevel1Mode(29);
13289  break;
13290  }
13291  Utilities->CallLogPop(103);
13292 }
13293 
13294 // ---------------------------------------------------------------------------
13295 
13297 {
13298  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
13299  if(Level1Mode != TrackMode)
13300  {
13301  // No further recursion in BaseMode so OK
13302  Level1Mode = BaseMode;
13303  SetLevel1Mode(20);
13304  Utilities->CallLogPop(1115);
13305  return;
13306  }
13308  {
13309  Utilities->CallLogPop(104);
13310  return;
13311  }
13312  switch(Level2TrackMode) // use the data member
13313  {
13314  case AddTrack:
13316  InfoPanel->Visible = true;
13317  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
13318  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
13319  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
13320  TrackElementPanel->Visible = true;
13321  TrackElementPanel->Enabled = true;
13322  SigAspectButton->Visible = true;
13323  SigAspectButton->Enabled = true;
13324  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
13326  SetLengthsButton->Enabled = false;
13327  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
13328  {
13329  SetLengthsButton->Enabled = true;
13330  }
13331  UserGraphicReselectPanel->Visible = false;
13332  SelectLengthsFlag = false; // in case still set though probably won't be
13333  break;
13334 
13335  case AddGraphic:
13336  InfoPanel->Visible = true;
13337  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
13338  break;
13339 
13340  case SelectGraphic:
13341  InfoPanel->Visible = true;
13342  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
13343  break;
13344 
13345  case GapSetting:
13346  int HLoc, VLoc, Count;
13347  Count = Track->NumberOfGaps(0);
13348  if(div(Count, 2).rem == 1) // condition OK
13349  {
13350  ShowMessage("Can't connect, there are an odd number of gaps");
13352  SetLevel1Mode(77);
13354  // No further recursion in AddTrack so OK
13355  SetLevel2TrackMode(40);
13356  Utilities->CallLogPop(105);
13357  return;
13358  }
13359  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
13360  // need to call this here to start gap setting process off,
13361  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
13362  // complete) or no more gaps to be highlighted
13363  {
13364  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
13365  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
13367  SetLevel1Mode(78);
13369  // No further recursion in AddTrack so OK
13370  SetLevel2TrackMode(41);
13371  Utilities->CallLogPop(106);
13372  return; // all gaps set
13373  }
13374  InfoPanel->Visible = true;
13375  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
13376  UserGraphicReselectPanel->Visible = false;
13378  break;
13379 
13380  case AddText:
13381  InfoPanel->Visible = true;
13382  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
13383  if(TextHandler->TextVectorSize(13) > 0)
13384  {
13385  MoveTextOrGraphicButton->Enabled = true;
13386  }
13387  else
13388  {
13389  MoveTextOrGraphicButton->Enabled = false;
13390  }
13391  UserGraphicReselectPanel->Visible = false;
13392  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
13393  break;
13394 
13395  case MoveTextOrGraphic:
13396  InfoPanel->Visible = true;
13397  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
13398  UserGraphicReselectPanel->Visible = false;
13399  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
13400  break;
13401 
13402  case AddLocationName:
13403  InfoPanel->Visible = true;
13404  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
13405  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
13406  UserGraphicReselectPanel->Visible = false;
13407  SetTrackBuildImages(12);
13408  break;
13409 
13410  case DistanceStart:
13411  InfoPanel->Visible = true;
13412  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
13413  DistanceKey->Visible = true;
13414  LengthConversionPanel->Visible = true;
13415  SpeedConversionPanel->Visible = true;
13416  UserGraphicReselectPanel->Visible = false;
13417  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
13418  break;
13419 
13420  case DistanceContinuing:
13421  InfoPanel->Visible = true;
13422  if(ConstructPrefDir->PrefDirSize() == 1)
13423  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
13424  else
13425  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
13426  UserGraphicReselectPanel->Visible = false;
13427  ClearandRebuildRailway(54); // to remove earlier end marker if present
13428  break;
13429 
13430  case TrackSelecting:
13431  Track->CopyFlag = false;
13432  if(!SelectionValid)
13433  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
13434  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
13435  // ReselectMenuItemClick)
13436  InfoPanel->Visible = true;
13437  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13438  SelectMenuItem->Enabled = false;
13439  ReselectMenuItem->Enabled = false;
13440  CancelSelectionMenuItem->Enabled = true;
13441  UserGraphicReselectPanel->Visible = false;
13442  break;
13443 
13444  case CopyMoving:
13445  Track->CopyFlag = true;
13446  InfoPanel->Visible = true;
13447  InfoPanel->Caption = "COPYING: Left click in selection && drag";
13448  CutMenuItem->Enabled = false;
13449  CopyMenuItem->Enabled = false;
13450  FlipMenuItem->Enabled = false;
13451  MirrorMenuItem->Enabled = false;
13452  RotRightMenuItem->Enabled = false;
13453  RotLeftMenuItem->Enabled = false;
13454  RotateMenuItem->Enabled = false;
13455  PasteMenuItem->Enabled = true;
13456 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying
13457  DeleteMenuItem->Enabled = false;
13458  SelectLengthsMenuItem->Enabled = false;
13459  SelectBiDirPrefDirsMenuItem->Visible = false;
13460  CancelSelectionMenuItem->Enabled = false;
13464  UserGraphicReselectPanel->Visible = false;
13465  break;
13466 
13467  case CutMoving:
13468  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13469  // erase track elements within selected region
13470  Track->CopyFlag = false;
13471  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false; ;
13472  int ErasedTrackVectorPosition;
13473  Screen->Cursor = TCursor(-11); // Hourglass;
13474  InfoPanel->Visible = true;
13475  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
13476  InfoPanel->Update();
13477  for(int H = SelectRect.left; H < SelectRect.right; H++)
13478  {
13479  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13480  {
13481  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13482  if(EraseSuccessfulFlag)
13483  {
13484  if(ErasedTrackVectorPosition > -1)
13485  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
13486  NeedToLink = true;
13487  }
13488  }
13489  }
13490  // erase text elements within selected region
13491  int LowSelectHPos = SelectRect.left * 16;
13492  int HighSelectHPos = SelectRect.right * 16;
13493  int LowSelectVPos = SelectRect.top * 16;
13494  int HighSelectVPos = SelectRect.bottom * 16;
13495  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13496  {
13497  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13498  TextPtr--) // reverse to prevent skipping during erase
13499  {
13500  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13501  HighSelectVPos))
13502  {
13503  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13504  {;
13505  } // unused condition
13506  TextChangesMade = true;
13507  }
13508  }
13509  }
13510  // erase graphic elements that fall wholly within region to be overwritten
13511  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13512  {
13513  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13514  GraphicPtr--) // reverse to prevent skipping during erase
13515  {
13516  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13517  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13518  {
13519  Track->UserGraphicVector.erase(GraphicPtr);
13520  GraphicChangesMade = true;
13521  }
13522  }
13523  }
13524  Track->CheckMapAndTrack(11); // test
13525  Track->CheckMapAndInactiveTrack(10); // test
13526  Track->CheckLocationNameMultiMap(19); // test
13527  Screen->Cursor = TCursor(-2); // Arrow;
13528  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13529  // if track not linked to begin with then becomes linked if NeedToLink false
13530  if(NeedToLink)
13531  Track->SetTrackFinished(false); // corrected for v2.1.0
13532  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
13533  CutMenuItem->Enabled = false;
13534  CopyMenuItem->Enabled = false;
13535  FlipMenuItem->Enabled = false;
13536  MirrorMenuItem->Enabled = false;
13537  RotRightMenuItem->Enabled = false;
13538  RotLeftMenuItem->Enabled = false;
13539  RotateMenuItem->Enabled = false;
13540  PasteMenuItem->Enabled = true;
13541 // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting
13542  DeleteMenuItem->Enabled = false;
13543  SelectLengthsMenuItem->Enabled = false;
13544  SelectBiDirPrefDirsMenuItem->Visible = false;
13545  CancelSelectionMenuItem->Enabled = false;
13548  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13549  {
13550  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
13551  }
13552  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
13553  UserGraphicReselectPanel->Visible = false;
13555  } break;
13556 
13557  case Pasting:
13558  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13561  int HDiff = SelectBitmapHLoc - SelectRect.left;
13562  int VDiff = SelectBitmapVLoc - SelectRect.top;
13563  bool NeedToLink = false;
13564  bool TrackLinkingRequiredFlag;
13565  Screen->Cursor = TCursor(-11); // Hourglass;
13566  InfoPanel->Visible = true;
13567  InfoPanel->Caption = "PASTING: Please wait";
13568  InfoPanel->Update();
13569 // erase track elements
13570  int LowSelectHLoc = SelectBitmapHLoc;
13571  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
13572  int LowSelectVLoc = SelectBitmapVLoc;
13573  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
13574  bool TrackEraseSuccessfulFlag; // needed but not used here
13575  int ErasedTrackVectorPosition;
13576 // new quick method of erasing, only need H & V values
13577  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
13578  {
13579  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
13580  {
13581  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
13582  if(ErasedTrackVectorPosition > -1)
13583  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
13584  }
13585  }
13586 
13587 // erase text elements that fall within region to be overwritten
13588  int LowSelectHPos = SelectBitmapHLoc * 16;
13589  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
13590  int LowSelectVPos = SelectBitmapVLoc * 16;
13591  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
13592  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13593  {
13594  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13595  TextPtr--) // reverse to prevent skipping during erase
13596  {
13597  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13598  HighSelectVPos))
13599  {
13600  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13601  {;
13602  } // unused condition
13603  }
13604  }
13605  }
13606 // erase graphic elements that fall wholly within region to be overwritten
13607  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13608  {
13609  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13610  GraphicPtr--) // reverse to prevent skipping during erase
13611  {
13612  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13613  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13614  {
13615  Track->UserGraphicVector.erase(GraphicPtr);
13616  }
13617  }
13618  }
13619  // change the H & V values in SelectVector to the new positions in case Reselect chosen
13620  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13621  {
13622  Track->SelectVectorAt(35, x).HLoc += HDiff;
13623  Track->SelectVectorAt(1, x).VLoc += VDiff;
13624  }
13625 
13626  // add the new track elements
13627  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13628  {
13629  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
13630  {
13631  Track->SelectVectorAt(80, x).LocationName = "";
13633  }
13634  bool InternalChecks = false;
13635 // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
13636 // {
13638  TrackLinkingRequiredFlag, InternalChecks);
13639  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
13640 // }
13641 /* drop this in v2.4.0 as all pastes are past with attributes
13642  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
13643  {
13644  int Aspect;
13645  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
13646  //this combination allows the funtion to distinguish between adding track and plotting with attributes
13647  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
13648  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
13649  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
13650  else Aspect = 4;
13651  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
13652  }
13653 */
13654  if(TrackLinkingRequiredFlag)
13655  NeedToLink = true;
13656  }
13657 
13658  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
13659  {
13660  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
13661  {
13662  TextPtr->HPos += HDiff * 16;
13663  TextPtr->VPos += VDiff * 16;
13664  AnsiString TempString = TextPtr->TextString;
13665  // have to create a new TextItem in order to create a new Font object
13666 /* drop in v2.4.0 as all pastes are paste with attributes
13667  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
13668  {
13669  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
13670  //use in PastingWithAttributes
13671  {
13672  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
13673  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
13674  }
13675  else TextPtr->TextString = ""; //delete the name for a simple paste
13676  }
13677 */
13678 // else //if pasting with attributes paste all text but strip the '##**' prefix if present
13679 // {
13680  if(TextPtr->TextString.SubString(1, 4) == "##**")
13681  {
13682  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
13683  if(Track->CopyFlag)
13684  {
13685  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
13686  TempString = "";
13687  }
13688  }
13689  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
13691 // }
13692  }
13693  }
13694  // add new graphic items
13695  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
13696  { // keep contents of SelectVector valid in case reselect
13697  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
13698  GraphicPtr++)
13699  {
13700  GraphicPtr->HPos += HDiff * 16; // for reselect
13701  GraphicPtr->VPos += VDiff * 16; // for reselect
13702  Track->UserGraphicVector.push_back(*GraphicPtr);
13703  }
13704  }
13705  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
13706  Track->CopyFlag = false;
13707  Track->CheckMapAndTrack(7); // test
13708  Track->CheckMapAndInactiveTrack(7); // test
13709  Track->CheckLocationNameMultiMap(7); // test
13710  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13711  // if track not linked to begin with then becomes linked if NeedToLink false
13712  if(NeedToLink)
13713  Track->SetTrackFinished(false); // corrected for v2.1.0
13714  Screen->Cursor = TCursor(-2); // Arrow;
13715  SetTrackBuildImages(14);
13718  SetLevel1Mode(79);
13720  // No further recursion in AddTrack so OK
13721  UserGraphicReselectPanel->Visible = false;
13722  SetLevel2TrackMode(42);
13723  } break;
13724 
13725  case Deleting:
13726  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13727  Track->CopyFlag = false;
13728  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
13729  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
13730  if(button == IDNO)
13731  {
13732  break;
13733  }
13734  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
13735  int ErasedTrackVectorPosition;
13736  Screen->Cursor = TCursor(-11); // Hourglass;
13737  InfoPanel->Visible = true;
13738  InfoPanel->Caption = "DELETING: Please wait";
13739  InfoPanel->Update();
13740  for(int H = SelectRect.left; H < SelectRect.right; H++)
13741  {
13742  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13743  {
13744  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13745  if(EraseSuccessfulFlag)
13746  {
13747  if(ErasedTrackVectorPosition > -1)
13748  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
13749  NeedToLink = true;
13750  }
13751  }
13752  }
13753  // erase text elements that fall within selected region
13754  int LowSelectHPos = SelectRect.left * 16;
13755  int HighSelectHPos = SelectRect.right * 16;
13756  int LowSelectVPos = SelectRect.top * 16;
13757  int HighSelectVPos = SelectRect.bottom * 16;
13758  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13759  {
13760  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13761  TextPtr--) // reverse to prevent skipping during erase
13762  {
13763  AnsiString Check = TextPtr->TextString;
13764  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13765  HighSelectVPos))
13766  {
13767  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13768  {;
13769  } // unused condition
13770  TextChangesMade = true;
13771  }
13772  }
13773  }
13774  // erase graphic elements that fall within selected region
13775  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13776  {
13777 
13778 //Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
13779 
13780 // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
13781 // GraphicPtr--) // reverse to prevent skipping during erase
13782 
13783 //i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
13784 //corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
13785 
13786  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13787  GraphicPtr--) // reverse to prevent skipping during erase
13788  {
13789  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13790  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13791  {
13792  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
13793  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
13794  {
13795  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
13796  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
13797  (UserGraphicPtr->FileName == GraphicPtr->FileName))
13798  {
13799  Track->UserGraphicVector.erase(UserGraphicPtr);
13800  GraphicChangesMade = true;
13801  }
13802  }
13803  }
13804  }
13805  }
13806  // clear the selectvectors
13808  TextHandler->SelectTextVector.clear();
13809  Track->SelectGraphicVector.clear();
13810  Track->CheckMapAndTrack(10); // test
13811  Track->CheckMapAndInactiveTrack(9); // test
13812  Track->CheckLocationNameMultiMap(15); // test
13813  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13814  // if track not linked to begin with then becomes linked if NeedToLink false
13815  if(NeedToLink)
13816  Track->SetTrackFinished(false); // corrected for v2.1.0
13817  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13818  {
13819  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
13820  }
13821  Screen->Cursor = TCursor(-2); // Arrow;
13824  SetLevel1Mode(80);
13826  // No further recursion in AddTrack so OK
13827  UserGraphicReselectPanel->Visible = false;
13828  SetLevel2TrackMode(43);
13829  } break;
13830 
13831  default:
13832  // No further recursion in TrackMode so OK
13833  Track->CopyFlag = false;
13835  SetLevel1Mode(21);
13836  UserGraphicReselectPanel->Visible = false;
13837  break;
13838  }
13839  Utilities->CallLogPop(107);
13840 }
13841 
13842 // ---------------------------------------------------------------------------
13843 
13845 {
13846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
13847  if(Level1Mode != PrefDirMode)
13848  {
13849  // No further recursion in BaseMode so OK
13850  Level1Mode = BaseMode;
13851  SetLevel1Mode(22);
13852  Utilities->CallLogPop(108);
13853  return;
13854  }
13856  {
13857  Utilities->CallLogPop(109);
13858  return;
13859  }
13860 
13861  switch(Level2PrefDirMode) // use the data member
13862  {
13863  case PrefDirContinuing:
13864  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13865  InfoPanel->Visible = true;
13866  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
13867  {
13868  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
13869  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
13870  }
13871  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
13872  DeleteOnePrefDirButton->Enabled = false;
13873  bool LeadingPointsAtLastElement = false;
13874  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
13875  {
13876  if(LeadingPointsAtLastElement) // size must be > 1
13877  {
13878  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
13879  DeleteOnePrefDirButton->Enabled = true;
13880  }
13881  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
13882  {
13883  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
13884  }
13885  }
13886  else // size > 1 & EndPossible
13887  {
13888  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
13889  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
13890  {
13891  AddPrefDirButton->Enabled = true;
13892  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
13893  }
13894  DeleteOnePrefDirButton->Enabled = true;
13895  }
13896  ExitPrefDirButton->Enabled = true;
13897  ClearandRebuildRailway(40); // to show truncated PrefDirs
13898  } break;
13899 
13900  case PrefDirSelecting:
13901  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
13902  InfoPanel->Visible = true;
13903  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13904  SelectMenuItem->Enabled = false;
13905  ReselectMenuItem->Enabled = false;
13906  CancelSelectionMenuItem->Enabled = true;
13907  break;
13908 
13909  default:
13910  // No further recursion in PrefDirMode so OK
13912  SetLevel1Mode(23);
13913  break;
13914  }
13915  Utilities->CallLogPop(110);
13916 }
13917 
13918 // ---------------------------------------------------------------------------
13919 
13921 {
13922  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
13923  if(Level1Mode != OperMode)
13924  {
13925  // No further recursion in BaseMode so OK
13926  Level1Mode = BaseMode;
13927  SetLevel1Mode(24);
13928  Utilities->CallLogPop(111);
13929  return;
13930  }
13931  if(Level2OperMode == NoOperMode)
13932  {
13933  Utilities->CallLogPop(112);
13934  return;
13935  }
13936  CallingOnButton->Visible = true;
13937  PresetAutoSigRoutesButton->Visible = false;
13938  switch(Level2OperMode) // use the data member
13939  {
13940  case Operating:
13941  { // have to use braces as otherwise the default case bypasses the initialisation of local variables
13942  OperateButton->Enabled = true;
13943  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
13944  ExitOperationButton->Enabled = true;
13945  TTClockAdjButton->Enabled = false;
13946  if(TTClockSpeed == 2)
13947  TTClockSpeedLabel->Caption = "x2";
13948  else if(TTClockSpeed == 4)
13949  TTClockSpeedLabel->Caption = "x4";
13950  else if(TTClockSpeed == 8)
13951  TTClockSpeedLabel->Caption = "x8";
13952  else if(TTClockSpeed == 16)
13953  TTClockSpeedLabel->Caption = "x16";
13954  else if(TTClockSpeed == 0.5)
13955  TTClockSpeedLabel->Caption = "x1/2";
13956  else if(TTClockSpeed == 0.25)
13957  TTClockSpeedLabel->Caption = "x1/4";
13958  else if(TTClockSpeed == 0.125)
13959  TTClockSpeedLabel->Caption = "x1/8";
13960  else if(TTClockSpeed == 0.0625)
13961  TTClockSpeedLabel->Caption = "x1/16";
13962  else
13963  {
13964  TTClockSpeed = 1;
13965  TTClockSpeedLabel->Caption = "x1";
13966  }
13967  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
13969  {
13970  // send message to performance log
13971  if(TTClockSpeed == 2)
13972  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
13973  else if(TTClockSpeed == 4)
13974  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
13975  else if(TTClockSpeed == 8)
13976  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
13977  else if(TTClockSpeed == 16)
13978  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
13979  else if(TTClockSpeed == 0.5)
13980  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
13981  else if(TTClockSpeed == 0.25)
13982  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
13983  else if(TTClockSpeed == 0.125)
13984  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
13985  else if(TTClockSpeed == 0.0625)
13986  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
13987  else
13988  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
13989  }
13990  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
13991  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
13992  {
13993  // send message to performance log
13994  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
13995  int HoursIncrease = 0;
13996  while(MinsIncrease >= 60)
13997  {
13998  HoursIncrease++;
13999  MinsIncrease -= 60;
14000  }
14001  if(HoursIncrease == 0)
14002  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
14003  else if(MinsIncrease == 0)
14004  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
14005  else
14006  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
14007  Display->PerformanceLog(13, TimeMessage);
14008  }
14009  WarningHover = false;
14012  {
14013  MTBFEditBox->Visible = true;
14014  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
14015  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
14016  MTBFLabel->Visible = true;
14017  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14019  }
14020  else
14021  {
14022  MTBFEditBox->Visible = false;
14023  MTBFEditBox->Text = "";
14024  MTBFLabel->Visible = false;
14025  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14027  }
14028  TrainController->BaseTime = TDateTime::CurrentDateTime();
14029 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
14030  } break;
14031 
14032  case Paused:
14033  OperateButton->Enabled = true;
14034  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
14035  ExitOperationButton->Enabled = true;
14036  TTClockAdjButton->Enabled = true;
14041 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
14044  break;
14045 
14046  // don't need a separate case for PreStart
14047 
14048  default:
14049  // No further recursion in OperMode so OK
14050  Level1Mode = OperMode;
14051  SetLevel1Mode(25);
14052  break;
14053  }
14054  Utilities->CallLogPop(113);
14055 }
14056 
14057 // ---------------------------------------------------------------------------
14058 
14059 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
14060 {
14061  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
14062  float LockDelay = 120.0;
14063 
14064  if(!AllRoutes->LockedRouteVector.empty())
14065  {
14066  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
14067  {
14068  bool BreakFlag = false;
14069  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
14070  {
14071  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
14072  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
14073  {
14074  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
14075  AnsiString(LRVIT->LastTrackVectorPosition));
14076  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
14077  { // examine the element one earlier in the route than the last
14078  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
14079  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
14080  {
14081  BreakFlag = true;
14082  }
14083  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
14084  if(BreakFlag)
14085  break; // train removed earlier element from route so stop here
14086  }
14087  if(!BreakFlag)
14088  { // still need to remove the element at the TruncateTrackVectorPosition
14089  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
14090  {
14091  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
14092  Route.LastElementPtr(20)->GetELink());
14093  }
14094  }
14095  AllRoutes->CheckMapAndRoutes(10); // test
14096  AllRoutes->LockedRouteVector.erase(LRVIT);
14097  if(!Display->ZoomOutFlag)
14098  ClearandRebuildRailway(17); // to get rid of route graphics
14100  }
14101  }
14102  else
14103  {
14104  AllRoutes->LockedRouteVector.erase(LRVIT);
14105  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
14106  // hence no longer needed so get rid of it
14107  }
14108  }
14109  }
14110  Utilities->CallLogPop(743);
14111 }
14112 
14113 // ---------------------------------------------------------------------------
14114 
14115 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
14116 {
14117  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
14119  {
14121  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
14122  AutoSigVectorIT--)
14123  {
14124  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
14125  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
14126  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
14127  TPrefDirElement TempPrefDirElement;
14128  int TempLockedVectorNumber;
14129  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
14130  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
14131  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
14132  // route exiting at a continuation
14133  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
14134  {
14135  continue;
14136  }
14137  // end of additions
14138  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
14139  {
14140  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
14141  AutoSigVectorIT->AccessNumber++;
14142  continue;
14143  }
14144  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
14145  {
14146  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
14147  AutoSigVectorIT->AccessNumber++;
14148  continue;
14149  }
14150  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
14151  {
14152  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
14153  AutoSigVectorIT->AccessNumber++;
14154  continue;
14155  }
14156  }
14157  // examine all vector for any expired values & erase
14158  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
14159  AutoSigVectorIT--)
14160  {
14161  if(AutoSigVectorIT->AccessNumber > 2)
14162  {
14163  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
14164  }
14165  }
14166  }
14167  Utilities->CallLogPop(744);
14168 }
14169 
14170 // ---------------------------------------------------------------------------
14171 
14173 {
14174  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
14175 
14176  TPoint MousePoint = Mouse->CursorPos;
14177  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
14178  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
14179 
14180  if((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0))
14181  {
14182  FloatingPanel->Visible = false;
14183  Utilities->CallLogPop(1432);
14184  return;
14185  }
14186 
14187  if(PerformancePanel->Visible)
14188  {
14189  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
14190  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14191  (PerformancePanel->Top + PerformancePanel->Height)))
14192  { // dont show floating window if mouse over performance panel
14193  FloatingPanel->Visible = false;
14194  Utilities->CallLogPop(1715);
14195  return;
14196  }
14197  }
14198 
14199  if(OperatorActionPanel->Visible) // added at v2.3.0 as showed info from behind panel - thanks to Xeon who notified me in email of 15/10/19
14200  {
14201  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
14202  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14203  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
14204  { // dont show floating window if mouse over OperatorActionPanel
14205  FloatingPanel->Visible = false;
14206  Utilities->CallLogPop(2098);
14207  return;
14208  }
14209  }
14210 
14211  if(TimetableEditPanel->Visible) // added at v2.5.1 as showed track info behind panel
14212  {
14213  if((MousePoint.x >= TimetableEditPanel->Left) && (MousePoint.x <= (TimetableEditPanel->Left + TimetableEditPanel->Width)) &&
14214  ((MousePoint.y - ClientOrigin.y) >= TimetableEditPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14215  (TimetableEditPanel->Top + TimetableEditPanel->Height)))
14216  { // dont show floating window if mouse over TimetableEditPanel
14217  FloatingPanel->Visible = false;
14218  Utilities->CallLogPop(2240);
14219  return;
14220  }
14221  }
14222 
14223  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
14224 
14225  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
14226  int HLoc, VLoc;
14227 
14228  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
14229 
14230  if(Display->ZoomOutFlag)
14231  {
14232  Utilities->CallLogPop(1123);
14233  return;
14234  }
14235  if(TrackInfoOnOffMenuItem->Caption == "Hide")
14236  {
14237  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
14238  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
14239  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
14240  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
14241  AnsiString SigAspectString = ""; // new at version 0.6
14242  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
14243  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
14244  TTrackElement ActiveTrackElement, InactiveTrackElement;
14245  if(InactiveTrackFoundFlag)
14246  {
14247  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
14248  IATrackSN = InactiveTrackElement.LocationName;
14249  }
14250  if(ActiveTrackFoundFlag)
14251  {
14252  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
14253  ATrackSN = ActiveTrackElement.LocationName;
14254  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
14255  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
14256  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
14257  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
14258  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
14259  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
14260  {
14261  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
14262  }
14263  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
14264  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
14265  {
14266  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
14267  }
14268  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
14269  {
14270  TwoTrack = true;
14271  }
14272  Length01Str = AnsiString(ActiveTrackElement.Length01);
14273  if(Length01Str == "-1")
14274  Length01Str = "Not Set";
14275  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
14276  if(SpeedLimit01Str == "-1")
14277  SpeedLimit01Str = "Not Set";
14278  if(TwoTrack)
14279  {
14280  Length23Str = AnsiString(ActiveTrackElement.Length23);
14281  if(Length23Str == "-1")
14282  Length23Str = "Not Set"; // shouldn't be -1 but leave in
14283  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
14284  if(SpeedLimit23Str == "-1")
14285  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
14286  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
14287  {
14288  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
14289  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
14290  }
14291  else if(ActiveTrackElement.TrackType == Points)
14292  {
14293  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
14294  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
14295  SpeedLimit23Str + " km/h";
14296  }
14297  else if(ActiveTrackElement.TrackType == Crossover)
14298  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
14299  {
14300  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
14301  {
14302  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
14303  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
14304  }
14305  else if(ActiveTrackElement.SpeedTag == 47)
14306  {
14307  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
14308  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
14309  }
14310  else if(ActiveTrackElement.SpeedTag == 45)
14311  {
14312  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
14313  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
14314  }
14315  else if(ActiveTrackElement.SpeedTag == 44)
14316  {
14317  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
14318  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
14319  }
14320  else if(ActiveTrackElement.SpeedTag == 16)
14321  {
14322  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
14323  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
14324  SpeedLimit23Str + " km/h";
14325  }
14326  }
14327  else // bridge
14328  {
14329  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
14330  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
14331  }
14332  }
14333  else
14334  {
14335  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
14336  }
14337  }
14338  if(ActiveTrackFoundFlag)
14339  {
14340  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
14341  // in case wish to resurrect this line for any reason
14342  ShowTrackFloatFlag = true;
14343  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
14344  {
14345  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14346  }
14347  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
14348  {
14349  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14350  }
14351 
14352  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
14353  {
14354  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14355  }
14356 
14357  else // no timetable or location name, just track
14358  {
14359  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
14360  }
14361  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
14362  {
14363  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
14364  {
14365  SigAspectString = "\nThree-aspect signal";
14366  }
14367  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
14368  {
14369  SigAspectString = "\nTwo-aspect signal";
14370  }
14371  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
14372  {
14373  SigAspectString = "\nGround signal";
14374  }
14375  else
14376  {
14377  SigAspectString = "\nFour-aspect signal";
14378  }
14379  TrackFloat += SigAspectString;
14380  }
14381  } // if(ActiveFoundFlag)
14382  else if(InactiveTrackFoundFlag) // inactive element but no active element,
14383  // i.e. concourse or non-station name at a blank element
14384  {
14385  ShowTrackFloatFlag = true;
14386  if(InactiveTrackElement.TrackType != Parapet)
14387  {
14388  if(IATrackSN == "")
14389  {
14390  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
14391  }
14392  else
14393  {
14394  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
14395  }
14396  }
14397  else // it is a parapet, just show the ID
14398  {
14399  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
14400  }
14401  }
14402  }
14403 // end of TrackFloat section
14404 
14405  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
14406  // if caption is 'Hide' label is required
14407  {
14408  bool FoundFlag;
14409  AnsiString FormatOneDPStr = "####0.0";
14410  AnsiString FormatNoDPStr = "#######0";
14411 // AnsiString Format5DPStr = "####0.00000"; //temporary
14412  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
14413  AnsiString SpecialStr = "", MaxSpeedStr = "";
14414  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
14415  if(FoundFlag)
14416  {
14417  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
14418  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
14419  {
14421  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14422  {
14423  ShowTrainStatusFloatFlag = true;
14424  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
14425  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
14426  double CurrSpeed;
14427  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
14428  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
14429  if(Train.BeingCalledOn)
14430  MaxSpeedStr = "30";
14431  else
14432  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
14433  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
14434  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
14435  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
14436  TDateTime TimeLeft;
14437  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14438  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
14439  HeadCode = Train.HeadCode;
14440  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
14441  {
14442  if(Train.RepeatNumber == 0)
14443  {
14444  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14445  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
14446  else
14447  ServiceReferenceInfo = "\nFirst service";
14448  }
14449  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
14450  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
14451  else
14452  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " +
14454  }
14455  else
14456  {
14457  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14458  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
14459  }
14460  if(Train.Stopped())
14461  {
14462  if(Train.SignallerStopped)
14463  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
14464  if(Train.NotInService)
14465  Status = "Not in service"; // not used so far but leave it in
14466  if(Train.StoppedAtBuffers)
14467  Status = "Stopped at buffers";
14468  if(Train.StoppedAtSignal)
14469  Status = "Stopped at signal";
14470  if(Train.StoppedForTrainInFront)
14471  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
14472  if(Train.StoppedAtLocation)
14473  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
14474  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
14475  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
14476  if(Train.StoppedWithoutPower)
14477  {
14478  if(Train.TrainFailed)
14479  Status = "Stopped without power - train failed";
14480  else
14481  Status = "Stopped without power";
14482  }
14483  if(Train.StoppedAfterSPAD)
14484  Status = "Stopped - signal passed at danger";
14485  if(Train.Derailed)
14486  Status = "Derailed";
14487  if(Train.Crashed)
14488  Status = "Crashed";
14489  CurrSpeed = 0;
14490  }
14491  else if(Train.OneLengthAccelDecel)
14492  {
14493  if(Train.FirstHalfMove)
14494  {
14495  Status = "Accelerating"; // just display a linear speed rise over half length
14496  BrakePCRate = 0; // reset to proper value during braking
14497  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
14498  }
14499  else
14500  {
14501  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14502  if(BrakePCRate < 55)
14503  Status = "Light braking";
14504  else if(BrakePCRate < 90)
14505  Status = "Heavy braking";
14506  else
14507  Status = "Emergency braking";
14508  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
14509  }
14510  }
14511  else if(Train.BrakeRate > 0.01)
14512  {
14513  if(BrakePCRate < 55)
14514  Status = "Light braking";
14515  else if(BrakePCRate < 90)
14516  Status = "Heavy braking";
14517  else
14518  Status = "Emergency braking";
14519  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
14520  }
14521 
14522  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
14523  {
14524  Status = "Accelerating"; // just display a linear speed rise over half length
14525  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
14526  }
14527 
14528  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
14529  {
14530  Status = "Accelerating";
14531  CurrSpeed = Train.ExitSpeedHalf +
14532  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
14533  }
14534 
14535  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
14536  {
14537  if(Train.PowerAtRail < 1)
14538  {
14539  if(Train.TrainFailed)
14540  {
14541  Status = "Coasting - train failed";
14542  }
14543  else
14544  {
14545  Status = "Coasting - no power";
14546  }
14547  CurrSpeed = Train.ExitSpeedFull;
14548  }
14549  else
14550  {
14551  Status = "Constant speed";
14552  CurrSpeed = Train.ExitSpeedFull;
14553  }
14554  }
14555 
14556  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
14557  {
14558  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
14559  {
14560  if(Train.TrainFailed)
14561  {
14562  Status = "Coasting - train failed";
14563  }
14564  else
14565  {
14566  Status = "Coasting - no power";
14567  }
14568  CurrSpeed = Train.ExitSpeedHalf;
14569  }
14570  else
14571  {
14572  Status = "Constant speed";
14573  CurrSpeed = Train.ExitSpeedHalf;
14574  }
14575  }
14576  if(Train.TimetableFinished)
14577  {
14578  if(Train.TrainMode == Signaller)
14579  NextStopStr = "At signaller's discretion";
14580  else
14581  NextStopStr = "None";
14582  }
14583  else
14584  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
14585  if(Train.TrainMode == Signaller)
14586  {
14587  SpecialStr = "Train under signaller control" + AnsiString('\n');
14588  }
14589  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
14590  {
14591  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
14592  }
14593 
14594  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
14595  if(RemTimeHalf < 0)
14596  RemTimeHalf = 0;
14597  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
14598  if(RemTimeFull < 0)
14599  RemTimeFull = 0;
14600  if(RemTimeHalf > 0)
14601  TimeLeft = RemTimeHalf;
14602  else
14603  TimeLeft = RemTimeFull;
14604  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
14605  if(Train.Stopped())
14606  TimeToNextMovementStr = "";
14607  if(Train.Stopped())
14608  {
14609  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
14610  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
14611  Status + '\n' + "Next: " + NextStopStr;
14612  }
14613  else
14614  {
14615  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
14616  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
14617  Status + ": " + CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
14618  }
14619  }
14620  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14621  {
14622  ShowTrainTTFloatFlag = true;
14623  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
14624  }
14625  }
14626 
14627  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
14628  // always give train information if a train present, but if not & either of train status or timetable info
14629  // selected then give next expected train to enter, or 'No trains expected'
14630  {
14631  TrainStatusFloat = "No trains expected";
14632  TrainTTFloat = "No timetable";
14633  float EntrySpeed;
14634  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
14635  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14636  ShowTrainStatusFloatFlag = true;
14637  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14638  ShowTrainTTFloatFlag = true;
14640  {
14643  {
14644  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
14645  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
14646  {
14647  CTEIt++;
14648  }
14650  {
14651  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
14652  AnsiString ServiceReferenceInfo = "";
14653  // Repeat information
14654  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
14655  {
14656  if(CTEIt->second.RepeatNumber == 0)
14657  {
14658  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14659  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
14660  else
14661  ServiceReferenceInfo = "\nFirst service";
14662  }
14663  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
14664  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
14665  else
14666  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " +
14667  TTDEPtr->ServiceReference;
14668  }
14669  else
14670  {
14671  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14672  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
14673  }
14674  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
14675  {
14676  SpecialStr = "\nTrain under signaller control";
14677  EntrySpeed = TTDEPtr->SignallerSpeed;
14678  if(EntrySpeed > LineSpeedLimit)
14679  EntrySpeed = LineSpeedLimit;
14680  }
14681  else
14682  {
14683  EntrySpeed = TTDEPtr->StartSpeed;
14684  if(EntrySpeed > LineSpeedLimit)
14685  EntrySpeed = LineSpeedLimit;
14686  }
14687  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
14688  {
14689  TDateTime TempTime = CTEIt->first;
14690 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14691  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14692  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " +
14693  Utilities->Format96HHMM(TempTime);
14694  }
14695  else
14696  {
14697  TDateTime TempTime = CTEIt->first;
14698 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14699  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14700  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " +
14701  Utilities->Format96HHMM(TempTime);
14702  }
14703  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14704  {
14705  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
14706  {
14707  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber,
14708  CTEIt->second.IncrementalMinutes, CTEIt->second.IncrementalDigits);
14709  }
14710  }
14711  }
14712  }
14713  }
14714  }
14715  }
14716  }
14717 
14718 // end of TrainFloat section
14719  AnsiString Caption;
14720 
14721  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14722  {
14723  FloatingPanel->Visible = false;
14724  Utilities->CallLogPop(1485);
14725  return; // return with label invisible
14726  }
14727  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14728  {
14729  Caption = TrackFloat;
14730  }
14731  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14732  {
14733  Caption = TrainStatusFloat;
14734  }
14735  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14736  {
14737  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14738  }
14739  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14740  {
14741  if(TrainStatusFloat == "No trains expected")
14742  Caption = TrainStatusFloat;
14743  else
14744  Caption = TrainTTFloat;
14745  }
14746  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14747  {
14748  if(TrainStatusFloat == "No trains expected")
14749  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14750  else
14751  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
14752  }
14753  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14754  {
14755  if(TrainStatusFloat == "No trains expected")
14756  Caption = TrainStatusFloat;
14757  else
14758  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
14759  }
14760  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14761  {
14762  if(TrainStatusFloat == "No trains expected")
14763  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14764  else
14765  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
14766  }
14767 
14768  int Left = ScreenX + MainScreen->Left + 16; // so lhs of window is one element to the right of the mouse pos
14769 
14770 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
14771 // offset 32 to the right and 95 down from the interface form
14772  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
14773  Left = ScreenX - FloatingPanel->Width + 16; // so rhs of window is one element to the left of the mouse pos (+32 would be at mouse pos)
14774  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
14775 
14776  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
14777  {
14778  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
14779  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
14780  // lose something then it's best to be from the bottom
14781  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
14782  // obscure the window
14783  {
14784  Top = 30;
14785  }
14786  }
14787  if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top))
14788  {
14789  FloatingPanel->Visible = false; // so doesn't flicker when reposition
14790  FloatingPanel->Left = Left;
14791  FloatingPanel->Top = Top;
14792  Utilities->CallLogPop(1917);
14793  return;
14794  }
14795 
14796  FloatingLabel->Caption = Caption;
14797  FloatingPanel->Visible = true;
14798  FloatingPanel->BringToFront();
14799  Utilities->CallLogPop(746);
14800 }
14801 
14802 // ---------------------------------------------------------------------------
14803 
14804 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
14805  // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
14806  // Gap flashing is cancelled on any mousedown event
14807 
14808  // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
14809 {
14810  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
14812  {
14813  if(WarningFlash)
14814  {
14815  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
14817  }
14818  else
14819  {
14820  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
14822  }
14823  }
14824 
14826  {
14827  if(WarningFlash)
14828  {
14833  Display->Update();
14834  }
14835  else
14836  {
14841  Display->Update();
14842  }
14843  }
14844 
14845 // deal with other flashing graphics
14847  {
14848  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
14849  {
14850  // cancel if train is moving & arrives on any part of flashing route
14852  {
14853  Track->RouteFlashFlag = false;
14855  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
14856  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
14857  Utilities->CallLogPop(75);
14858  return;
14859  }
14860 
14861  InfoPanel->Visible = true;
14862  if(Level2OperMode == PreStart)
14863  InfoPanel->Caption = "PRE-START: Route setting in progress";
14864  else
14865  InfoPanel->Caption = "OPERATING: Route setting in progress";
14866  if(WarningFlash)
14867  {
14869  }
14870  else
14871  {
14873  }
14874  }
14875  else
14876  {
14877 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
14878 // stop clock while converting route as can take several seconds
14879  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
14881  if(PreferredRouteFlag)
14883  else
14885  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
14886  TrainController->BaseTime = TDateTime::CurrentDateTime();
14888  Track->RouteFlashFlag = false;
14890  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
14891  }
14892  }
14893 
14894  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
14895  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
14896  // no need to call Clearand... as that is called when revert to normal mode
14897  {
14898  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
14899  {
14900  Track->RouteFlashFlag = false;
14901  if(PreferredRouteFlag)
14902  {
14904  }
14905  else
14906  {
14908  }
14909  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
14910  }
14911  }
14912 
14914  {
14915  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
14916  {
14917  // cancel if train is present on or enters a flashing point, either selected or diverging
14919  {
14921  Track->PointFlashFlag = false;
14923  Utilities->CallLogPop(76);
14924  return;
14925  }
14927  {
14929  Track->PointFlashFlag = false;
14931  Utilities->CallLogPop(77);
14932  return;
14933  }
14934 
14935  if(WarningFlash)
14936  {
14939  }
14940  else
14941  {
14943  }
14944  }
14945  else
14946  {
14951  {
14955  }
14957  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
14958  Track->PointFlashFlag = false;
14960  }
14961  }
14962 
14964  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
14965  {
14966  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
14967  {
14971  {
14974  }
14975  Track->PointFlashFlag = false;
14977  }
14978  }
14979 // deal with level crossings
14980  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
14981  {
14982  int H;
14983  int V;
14984  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
14985  {
14986  H = Track->ChangingLCVector.at(x).HLoc;
14987  V = Track->ChangingLCVector.at(x).VLoc;
14988  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
14989  // still flashing
14990  {
14991  if(WarningFlash)
14992  {
14993  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
14994  {
14995  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
14996  }
14997  else
14998  {
14999  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
15000  Track->ChangingLCVector.at(x).ConsecSignals, Display);
15001  }
15002  }
15003  else
15004  {
15005  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
15006  Track->ChangingLCVector.at(x).ConsecSignals, Display);
15007  }
15008  }
15009  else
15010  // flashing period finished
15011  {
15012  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
15013  {
15014  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
15015  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
15016  // attributes set to 2 when changing state, now reset to 0, no other actions needed
15017  }
15018  else
15019  // barriers lowering
15020  {
15021  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
15022  Track->ChangingLCVector.at(x).ConsecSignals, Display);
15023  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
15024  bool FoundFlag;
15025  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
15026  if(!FoundFlag)
15027  {
15028  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
15029  }
15030  int RouteNumber;
15031  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
15032  // don't need returned value of RouteType
15033  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
15034  {
15035  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
15036  }
15037  }
15038  }
15039  }
15040  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
15041  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector, reset the start timer (to time the barrier down period)
15042  // and erase the object from the ChangingLCVector
15043  {
15044  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
15045  {
15046  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
15047  {
15048  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
15049  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
15050  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
15051  }
15052  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
15053  }
15054  }
15055  }
15056  Utilities->CallLogPop(747);
15057 }
15058 
15059 // ---------------------------------------------------------------------------
15060 
15062  // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
15063 {
15064  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
15065 
15066 // set save railway buttons
15067  bool SaveRailwayButtonsFlag = true;
15068 
15069  SaveRailwayTBPButton->Visible = true;
15070  SaveRailwayPDPButton->Visible = true;
15071  SaveSessionButton->Visible = true;
15072  if(Level1Mode == OperMode)
15073  {
15075  {
15076  SaveRailwayButtonsFlag = false;
15077  }
15078  // set PresetAutoSigRoutesButton enabled or not
15079  // enable if PreStart & no routes set
15080  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()))
15081  {
15082  PresetAutoSigRoutesButton->Enabled = true;
15083  }
15084  else
15085  {
15086  PresetAutoSigRoutesButton->Enabled = false;
15087  }
15088  }
15089  else
15090  {
15092  {
15093  SaveRailwayButtonsFlag = false;
15094  }
15095  else if(SavedFileName != "")
15096  {
15097  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
15098  {
15099  if(!(Track->IsReadyForOperation()))
15100  {
15101  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
15102  }
15103  }
15104  }
15105  }
15106  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
15107  {
15108  SaveRailwayBaseModeButton->Visible = true;
15109  }
15110  else
15111  {
15112  SaveRailwayBaseModeButton->Visible = false;
15113  }
15114  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
15115  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
15116  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
15117  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
15118 
15119 // set formatted timetable menu item
15120  if(TimetableTitle == "")
15121  {
15122  ExportTTMenuItem->Enabled = false;
15123  }
15124  else
15125  {
15126  ExportTTMenuItem->Enabled = true;
15127  }
15128 
15129 // set info menu items
15131  {
15132  FloatingInfoMenu->Enabled = false;
15133  TrackInfoMenuItem->Enabled = false;
15134  TrainInfoMenuItem->Enabled = false;
15135  }
15136  else
15137  {
15138  FloatingInfoMenu->Enabled = true;
15139  TrackInfoMenuItem->Enabled = true;
15140  if(Level1Mode == OperMode)
15141  {
15142  TrainInfoMenuItem->Enabled = true;
15143  }
15144  else
15145  {
15146  TrainInfoMenuItem->Enabled = false;
15147  }
15148  }
15149 
15150 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
15151 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
15152 // there has been a legitimate change of state since the last access
15153 
15154  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
15155  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
15156 
15157  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
15158  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
15159  AnsiString OperatingPanelLabelCaptionStr = "Operation";
15160  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
15161 
15162  if(!Display->ZoomOutFlag)
15163  { // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
15165  ScreenLeftFlag = false; // 60 - 30
15167  ScreenRightFlag = false; // 60 - (60 - 30)
15169  ScreenUpFlag = false; // 36 - 18
15171  ScreenDownFlag = false; // 36 - (36 - 18)
15172  }
15173  else
15174  { // prevent if less than a quarter of a screen visible (width = 240, height = 144)
15176  ScreenLeftFlag = false; // 240 - 60
15178  ScreenRightFlag = false; // 240 - (240 - 60)
15180  ScreenUpFlag = false; // 144 - 36
15182  ScreenDownFlag = false; // 144 - (144 - 36)
15183  }
15185  {
15186  ZoomFlag = false;
15187  HomeFlag = false;
15188  NewHomeFlag = false;
15189  ScreenLeftFlag = false;
15190  ScreenRightFlag = false;
15191  ScreenUpFlag = false;
15192  ScreenDownFlag = false;
15193  }
15194 
15195  if(Display->ZoomOutFlag)
15196  {
15197 // NewHomeFlag = false;
15198  TrackBuildPanelEnabledFlag = false;
15199  TrackBuildPanelLabelCaptionStr = "Disabled";
15200  PrefDirPanelEnabledFlag = false;
15201  PrefDirPanelLabelCaptionStr = "Disabled";
15202  OperatingPanelEnabledFlag = false;
15203  OperatingPanelLabelCaptionStr = "Disabled";
15204  TimetablePanelEnabledFlag = false;
15205  TimetablePanelLabelCaptionStr = "Disabled";
15206  }
15207 
15208  if(Level1Mode == OperMode)
15209  {
15210  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true) //TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
15211  {
15212  MTBFEditBox->Enabled = false;
15213  OperatingPanelEnabledFlag = false;
15214  OperatingPanelLabelCaptionStr = "Disabled";
15215  ZoomFlag = false;
15216  HomeFlag = false;
15217  NewHomeFlag = false;
15218  ScreenLeftFlag = false;
15219  ScreenRightFlag = false;
15220  ScreenUpFlag = false;
15221  ScreenDownFlag = false;
15222  SaveOperatingImageMenuItem->Enabled = false;
15223  }
15224  else
15225  {
15226  MTBFEditBox->Enabled = true;
15227  SaveOperatingImageMenuItem->Enabled = true;
15228  }
15229  }
15230 
15231  if(LocationNameTextBox->Visible)
15232  {
15233  ZoomFlag = false;
15234  HomeFlag = false;
15235  NewHomeFlag = false;
15236  ScreenLeftFlag = false;
15237  ScreenRightFlag = false;
15238  ScreenUpFlag = false;
15239  ScreenDownFlag = false;
15240  }
15241 
15242  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
15243  {
15244  ZoomFlag = false;
15245  HomeFlag = false;
15246  NewHomeFlag = false;
15247  ScreenLeftFlag = false;
15248  ScreenRightFlag = false;
15249  ScreenUpFlag = false;
15250  ScreenDownFlag = false;
15251  }
15252 
15253  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
15254  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
15255  {
15256  ZoomFlag = false;
15257  HomeFlag = false;
15258  NewHomeFlag = false;
15259  ScreenLeftFlag = false;
15260  ScreenRightFlag = false;
15261  ScreenUpFlag = false;
15262  ScreenDownFlag = false;
15263  }
15264 
15267  {
15268  ZoomFlag = false;
15269  }
15270 
15271  if(ZoomFlag)
15272  ZoomButton->Enabled = true;
15273  else
15274  ZoomButton->Enabled = false;
15275  if(HomeFlag)
15276  HomeButton->Enabled = true;
15277  else
15278  HomeButton->Enabled = false;
15279  if(NewHomeFlag)
15280  NewHomeButton->Enabled = true;
15281  else
15282  NewHomeButton->Enabled = false;
15283  if(ScreenLeftFlag)
15284  ScreenLeftButton->Enabled = true;
15285  else
15286  ScreenLeftButton->Enabled = false;
15287  if(ScreenRightFlag)
15288  ScreenRightButton->Enabled = true;
15289  else
15290  ScreenRightButton->Enabled = false;
15291  if(ScreenUpFlag)
15292  ScreenUpButton->Enabled = true;
15293  else
15294  ScreenUpButton->Enabled = false;
15295  if(ScreenDownFlag)
15296  ScreenDownButton->Enabled = true;
15297  else
15298  ScreenDownButton->Enabled = false;
15299  if(OperatingPanelEnabledFlag)
15300  OperatingPanel->Enabled = true;
15301  else
15302  OperatingPanel->Enabled = false;
15303  if(TrackBuildPanelEnabledFlag)
15304  TrackBuildPanel->Enabled = true;
15305  else
15306  TrackBuildPanel->Enabled = false;
15307  if(PrefDirPanelEnabledFlag)
15308  PrefDirPanel->Enabled = true;
15309  else
15310  PrefDirPanel->Enabled = false;
15311  if(TimetablePanelEnabledFlag)
15312  TimetablePanel->Enabled = true;
15313  else
15314  TimetablePanel->Enabled = false;
15315  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
15316  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
15317  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
15318  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
15319 
15320 // check if any CallingOnFlags set & set button accordingly
15321  if(Display->ZoomOutFlag)
15322  {
15323  CallingOnButton->Enabled = false;
15324  CallingOnButton->Down = false;
15325  }
15326  else
15327  {
15328  if(Level2OperMode == Operating)
15329  {
15330  bool CallOnValid = false;
15331  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
15332  {
15334  {
15335  CallingOnButton->Enabled = true;
15336  CallOnValid = true;
15337  }
15338  }
15339  if(!CallOnValid)
15340  {
15341  CallingOnButton->Enabled = false;
15342  CallingOnButton->Down = false;
15343  }
15344  }
15345  else
15346  {
15347  CallingOnButton->Enabled = false;
15348  CallingOnButton->Down = false;
15349  }
15350  }
15351  Utilities->CallLogPop(970);
15352 }
15353 
15354 // ---------------------------------------------------------------------------
15355 
15356 void TInterface::ErrorLog(int Caller, AnsiString Message)
15357 {
15358 // create an error file for diagnostic purposes called on detection of a runtime error
15359 
15360 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
15361 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
15362 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
15363 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
15364 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
15365 // depending on the time taken to press Exit.
15366 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
15367 
15368  if(ErrorLogCalledFlag)
15369  return;
15370 
15371  ErrorLogCalledFlag = true;
15372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
15373  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
15374  SaveErrorFile();
15375  if((TempTTFileName != "") && FileExists(TempTTFileName))
15376  {
15377  DeleteFile(TempTTFileName);
15378  }
15379  Display->GetImage()->Visible = false;
15380  PerformancePanel->Visible = false;
15381  OperatorActionPanel->Visible = false; // new v2.2.0
15382  TrackBuildPanel->Visible = false;
15383  TrackElementPanel->Visible = false;
15384  LocationNameTextBox->Visible = false;
15385  TextBox->Visible = false;
15386  TrackLengthPanel->Visible = false;
15387  InfoPanel->Visible = false;
15388  PrefDirPanel->Visible = false;
15389  TimetablePanel->Visible = false;
15390  TimetableEditPanel->Visible = false;
15391  OperatingPanel->Visible = false;
15392  FloatingPanel->Visible = false;
15393  ModeMenu->Enabled = false;
15394  SigImagePanel->Visible = false; // new at v2.3.0
15395  FileMenu->Enabled = false;
15396  EditMenu->Enabled = false;
15397  FloatingInfoMenu->Enabled = false;
15398  HelpMenu->Enabled = false;
15399 // SaveHeaderMenu1->Enabled = false;
15400  ScreenLeftButton->Visible = false;
15401  ScreenRightButton->Visible = false;
15402  ScreenUpButton->Visible = false;
15403  ScreenDownButton->Visible = false;
15404  HomeButton->Visible = false;
15405  NewHomeButton->Visible = false;
15406  ZoomButton->Visible = false;
15407  PrefDirKey->Visible = false;
15408  DistanceKey->Visible = false;
15409  OutputLog1->Caption = "";
15410  OutputLog2->Caption = "";
15411  OutputLog3->Caption = "";
15412  OutputLog4->Caption = "";
15413  OutputLog5->Caption = "";
15414  OutputLog6->Caption = "";
15415  OutputLog7->Caption = "";
15416  OutputLog8->Caption = "";
15417  OutputLog9->Caption = "";
15418  OutputLog10->Caption = "";
15419  if(Caller == 113)
15420  {
15421  ErrorMessageStoreImage->Visible = true;
15422  }
15423  else
15424  {
15425  ErrorMessage->Visible = true;
15426  }
15427  ErrorButton->Visible = true;
15428  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
15429 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
15430 // is to close the program when the exit button is pressed
15431 }
15432 
15433 // ---------------------------------------------------------------------------
15434 
15436  // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
15437 {
15438  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
15439  if(FloatingPanel->Visible == false)
15440  {
15441  Utilities->CallLogPop(1205);
15442  return false;
15443  }
15444 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
15445  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
15446  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
15447  {
15448  Utilities->CallLogPop(1206);
15449  return false;
15450  }
15451  else
15452  {
15453  Utilities->CallLogPop(1207);
15454  return true;
15455  }
15456 }
15457 // ---------------------------------------------------------------------------
15458 
15459 void TInterface::SetCaption(int Caller)
15460 {
15461 /*
15462  NamedRailway; RlyFile; NamedTimetable
15463  n x x "New railway under development";
15464  y n x RailwayTitle + ": under development";
15465  y y n RailwayTitle + ": no timetable loaded";
15466  y y y RailwayTitle + ", " + TimetableTitle;
15467 */
15468 
15469  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
15470  if(RailwayTitle == "")
15471  Caption = "Railway: New railway under development";
15472  else if(!RlyFile)
15473  Caption = "Railway: " + RailwayTitle + " under development";
15474 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
15475  else if(TimetableTitle == "")
15476  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
15477  else
15478  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
15479  Utilities->CallLogPop(1208);
15480 }
15481 
15482 // ---------------------------------------------------------------------------
15483 
15484 void TInterface::ResetAll(int Caller)
15485 {
15486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
15487  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
15489  Track->GapFlashRedPosition = -1;
15490  Track->GapFlashFlag = false;
15491  Track->RouteFlashFlag = false;
15492  Track->PointFlashFlag = false;
15494  AutoSigsFlag = false;
15495  PreventGapOffsetResetting = false;
15496 
15497  Utilities->Clock2Stopped = false;
15498  TTClockSpeed = 1;
15499  TTClockSpeedLabel->Caption = "x1";
15500  Track->SetTrackFinished(false);
15502  CurrentSpeedButton = 0; // not assigned yet
15504  StartX = 0;
15505  StartY = 0;
15506  mbLeftDown = false;
15508  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
15510  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
15512  WarningFlashCount = 0;
15513 
15514  Level1Mode = BaseMode;
15515  SetLevel1Mode(26);
15516  RouteMode = None;
15517  PreferredRoute = true;
15518  ConsecSignalsRoute = true;
15519  DevelopmentPanel->Visible = false;
15520 
15521  MainScreen->Canvas->CopyMode = cmSrcCopy;
15522  FloatingPanel->Visible = false;
15523  OverallDistance = 0;
15524  OverallSpeedLimit = -1;
15525  AllRoutes->RouteTruncateFlag = false;
15526  CallingOnButton->Down = false;
15527  Display->ZoomOutFlag = false;
15528  ScreenGridFlag = false;
15529  InfoCaptionStore = "";
15530  ErrorLogCalledFlag = false;
15531  ErrorMessage->Visible = false;
15532  ErrorMessageStoreImage->Visible = false;
15533  TempCursorSet = false;
15534  TempCursor = TCursor(-2); // Arrow
15535  WholeRailwayMoving = false; // new at v2.1.0
15536 
15537  TrainController->TTClockTime = TDateTime(0); // default setting
15538  TTClockAdjPanel->Visible = false;
15540  ConflictPanel->Visible = false;
15541  SelectedTrainID = -1;
15542  SetTrackBuildImages(11);
15543 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
15544 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
15545 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
15546  Track->CalcHLocMinEtc(8);
15547  FileChangedFlag = false;
15548  RlyFile = false;
15549  SaveSessionFlag = false;
15550  LoadSessionFlag = false;
15551  SelectionValid = false;
15552  TimetableChangedFlag = false;
15553  SavedFileName = "";
15554  RailwayTitle = "";
15555  TimetableTitle = "";
15556  SetCaption(1);
15557  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
15558  // added for Beta v0.2b
15559  CreateEditTTTitle = ""; // as above
15560  AllRoutes->NextRouteID = 0;
15561  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
15562  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
15563 
15564  TempFont->Style.Clear();
15565  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
15566  TempFont->Size = 10;
15567  TempFont->Color = clB0G0R0;
15568  TempFont->Charset = (TFontCharset)(0);
15569  MainScreen->Canvas->Font->Assign(TempFont);
15570  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
15571  PerformancePanel->Left = MainScreen->Left;
15572  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
15573  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ; // new v2.2.0
15574  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
15575  // ScreenLeftButton->Left = ScreenRightButton->Left;
15576  // ScreenUpButton->Left = ScreenRightButton->Left;
15577  // ScreenDownButton->Left = ScreenRightButton->Left;
15578  // HomeButton->Left = ScreenRightButton->Left;
15579  // NewHomeButton->Left = ScreenRightButton->Left;
15580  // ZoomButton->Left = ScreenRightButton->Left;
15581  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
15582  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; ; // new v2.2.0
15583 
15584  delete TempFont;
15585  CtrlKey = false;
15586  ShiftKey = false;
15587  Utilities->CallLogPop(1209);
15588 }
15589 
15590 // ---------------------------------------------------------------------------
15591 
15593 {
15594  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
15595  if((Level1Mode == OperMode) || RlyFile)
15596  {
15597  TrackLinkedImage->Visible = false;
15598  TrackNotLinkedImage->Visible = false;
15599  GapsSetImage->Visible = false;
15600  GapsNotSetImage->Visible = false;
15601  LocationNamesSetImage->Visible = false;
15602  LocationNamesNotSetImage->Visible = false;
15603  Utilities->CallLogPop(1114);
15604  return;
15605  }
15606  else
15607  {
15608  if(!Track->NoActiveTrack(9))
15609  {
15610  if(Track->IsTrackFinished())
15611  {
15612  TrackLinkedImage->Visible = true;
15613  TrackNotLinkedImage->Visible = false;
15614  }
15615  else
15616  {
15617  TrackNotLinkedImage->Visible = true;
15618  TrackLinkedImage->Visible = false;
15619  }
15620  }
15621  else
15622  {
15623  TrackLinkedImage->Visible = false;
15624  TrackNotLinkedImage->Visible = false;
15625  }
15626 
15627  if(!Track->NoGaps(1))
15628  {
15629  if(Track->GapsUnset(6))
15630  {
15631  GapsNotSetImage->Visible = true;
15632  GapsSetImage->Visible = false;
15633  }
15634  else
15635  {
15636  GapsNotSetImage->Visible = false;
15637  GapsSetImage->Visible = true;
15638  }
15639  }
15640  else
15641  {
15642  GapsNotSetImage->Visible = false;
15643  GapsSetImage->Visible = false;
15644  }
15645 
15647  {
15648  if(Track->LocationsNotNamed(0))
15649  {
15650  LocationNamesSetImage->Visible = false;
15651  LocationNamesNotSetImage->Visible = true;
15652  }
15653  else
15654  {
15655  LocationNamesSetImage->Visible = true;
15656  LocationNamesNotSetImage->Visible = false;
15657  }
15658  }
15659  else
15660  {
15661  LocationNamesSetImage->Visible = false;
15662  LocationNamesNotSetImage->Visible = false;
15663  }
15664  }
15665  Utilities->CallLogPop(1113);
15666 }
15667 
15668 // ---------------------------------------------------------------------------
15669 
15670 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
15671 {
15672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
15673  FileChangedFlag = true;
15674  if(NonPrefDirChangesMade)
15675  {
15676  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
15677  {
15678  RailwayTitle = "";
15679  TimetableTitle = "";
15680  SavedFileName = "";
15681  RlyFile = false;
15682  }
15683  TimetableTitle = ""; // should have been reset already during user mode change but include here also
15684  SetTrackBuildImages(15);
15685  }
15686  SetCaption(2);
15687  Utilities->CallLogPop(1210);
15688 }
15689 
15690 // ---------------------------------------------------------------------------
15691 
15692 void TInterface::SaveSession(int Caller)
15693 { // ExcessLCDownMins saved as string after ***Interface*** see below
15694  try
15695  {
15696  TrainController->LogEvent("SaveSession");
15697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
15698  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
15699  Screen->Cursor = TCursor(-11); // Hourglass;
15700  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15701  // avoid characters in filename:= / \ : * ? " < > |
15702  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
15703  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
15704  SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
15705  "; " + TimetableTitle + ".ssn";
15706  std::ofstream SessionFile(SessionFileStr.c_str());
15707  if(!(SessionFile.fail()))
15708  {
15709  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
15710 // added ExcessLC... at v2.2.0 as omitted earlier
15711  SaveInterface(0, SessionFile);
15712  // save track elements
15713  Utilities->SaveFileString(SessionFile, "***Track***");
15714  if(Track->UserGraphicVector.empty())
15715  {
15716  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
15717  }
15718  else
15719  {
15720  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
15721  }
15722  // save text elements
15723  Utilities->SaveFileString(SessionFile, "***Text***");
15724  TextHandler->SaveText(2, SessionFile);
15725  // save PrefDir elements
15726  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
15727  EveryPrefDir->SavePrefDirVector(2, SessionFile);
15728  if(!Track->UserGraphicVector.empty())
15729  {
15730  // save user graphics
15731  Track->SaveUserGraphics(2, SessionFile);
15732  }
15733  // save routes
15734  Utilities->SaveFileString(SessionFile, "***Routes***");
15735  AllRoutes->SaveRoutes(0, SessionFile);
15736  // save LockedRoutes
15737  Utilities->SaveFileString(SessionFile, "***Locked routes***");
15738  TrainController->SaveSessionLockedRoutes(0, SessionFile);
15739  // save ContinuationAutoSigEntries
15740  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
15742  // save BarriersDownVector
15743  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
15744  Track->SaveSessionBarriersDownVector(0, SessionFile);
15745  // save timetable
15746  Utilities->SaveFileString(SessionFile, "***Timetable***");
15747  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr)))
15748  {
15749  SessionFile.close();
15750  DeleteFile(SessionFileStr);
15751  Screen->Cursor = TCursor(-2); // Arrow;
15752  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
15753  Utilities->CallLogPop(1150);
15754  return;
15755  }
15756  // save TimetableClock
15757  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
15758  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
15759 
15760  // save trains
15761  Utilities->SaveFileString(SessionFile, "***Trains***");
15762  TrainController->SaveSessionTrains(0, SessionFile);
15763  // save performance file
15764  Utilities->SaveFileString(SessionFile, "***Performance file***");
15765  SavePerformanceFile(0, SessionFile);
15766  Utilities->SaveFileString(SessionFile, "***End of performance file***");
15767 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
15768  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
15771  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
15772  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
15773  {
15775  {
15778  }
15779  }
15780  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
15781  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
15782 // end of v2.4.0 addition
15783  SessionFile.close();
15784  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
15785  RailwayTitle + "; " + TimetableTitle + ".ssn");
15786  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
15787  }
15788  else
15789  {
15790  TrainController->StopTTClockMessage(5, "Session file failed to open, session not saved. Ensure that there is a folder named " + SESSION_DIR_NAME +
15791  " in the folder where the 'Railway.exe' program file resides");
15792  }
15794  Screen->Cursor = TCursor(-2); // Arrow
15795  Utilities->CallLogPop(1141);
15796  }
15797  catch(const Exception &e)
15798  {
15799  ErrorLog(40, e.Message);
15800  }
15801 }
15802 
15803 // ---------------------------------------------------------------------------
15804 
15805 void TInterface::LoadSession(int Caller)
15806  // always loads in 'Paused' or 'PreStart' mode
15807 {
15808 // remember to load the timetable clock
15809 // no routes in build
15810 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
15811 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
15812 // set RlyFile true
15813  try
15814  {
15815  TrainController->LogEvent("LoadSession");
15816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
15817  if(!ClearEverything(4))
15818  {
15819  Utilities->CallLogPop(1145);
15820  return;
15821  }
15822  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
15823  if(LoadSessionDialog->Execute())
15824  {
15825  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
15826  Screen->Cursor = TCursor(-11); // Hourglass;
15827  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
15828  // if(true)
15829  {
15830  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
15831  if(!(SessionFile.fail()))
15832  {
15833  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
15834  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
15835  AnsiString TempString = Utilities->LoadFileString(SessionFile);
15836 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
15837 
15838  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
15839  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
15840  // can't find it or no value for Excess LCDownMins, either way count as zero
15841  {
15843  }
15844  else
15845  {
15846  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
15847  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
15848  {
15850  }
15851  else
15852  {
15853  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
15854  }
15855  } // end of v2.2.0 * v2.4.0 additions
15856 
15857  LoadInterface(0, SessionFile);
15858  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
15859  int TempDisplayOffsetV = Display->DisplayOffsetV;
15860  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
15861  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
15862  bool GraphicsFollow = false;
15863  // load track elements
15864  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
15865  Track->LoadTrack(4, SessionFile, GraphicsFollow);
15866  // load text elements
15867  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
15868  TextHandler->LoadText(1, SessionFile);
15869  // load PrefDir elements
15870  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
15871  EveryPrefDir->LoadPrefDir(1, SessionFile);
15872  if(GraphicsFollow)
15873  {
15874  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
15875  }
15877  {
15878  SessionFile.close();
15879  Screen->Cursor = TCursor(-2); // Arrow;
15880  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
15881  Utilities->CallLogPop(1438);
15882  return;
15883  }
15884  // load routes
15885  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
15886  if(!AllRoutes->LoadRoutes(0, SessionFile))
15887  {
15888  SessionFile.close();
15889  Screen->Cursor = TCursor(-2); // Arrow;
15890  ShowMessage("Corruption in route section of the session file, session can't be loaded");
15891  Utilities->CallLogPop(1439);
15892  return;
15893  }
15894  // load LockedRoutes
15895  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
15896  TrainController->LoadSessionLockedRoutes(0, SessionFile);
15897  // load ContinuationAutoSigEntries
15898  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
15900  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
15901  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
15902  if(TempString == "***BarriersDownVector***")
15903  {
15904  Track->LoadBarriersDownVector(0, SessionFile);
15905  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
15906  }
15907  // load timetable (marker "***Timetable***" already loaded)
15908  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
15909  {
15910  SessionFile.close();
15911  Screen->Cursor = TCursor(-2); // Arrow;
15912  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
15913  Utilities->CallLogPop(1151);
15914  return;
15915  }
15916  // TimetableTitle should be loaded at this stage - check
15917  if(TimetableTitle == "")
15918  {
15919  SessionFile.close();
15920  Screen->Cursor = TCursor(-2); // Arrow;
15921  throw Exception("TimetableTitle null in LoadSession");
15922  }
15923  // load timetable clock
15924  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
15925  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
15926  // load trains
15927  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
15928  TrainController->LoadSessionTrains(0, SessionFile);
15929  // load performance file + populate the performance log
15930  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
15931  // first reset the performance file name and open it before reloading it
15932  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15933  // avoid characters in filename:= / \ : * ? " < > |
15934  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
15935  TimetableTitle + ".txt";
15936  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
15937  if(Utilities->PerformanceFile.fail())
15938  {
15939  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
15940  " in the folder where the 'Railway.exe' program file resides");
15941  }
15942  // now reload the performance file
15943  LoadPerformanceFile(0, SessionFile);
15944  // addition at v2.4.0
15945  char TempChar;
15946  SessionFile.get(TempChar);
15947  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
15948  {
15949  SessionFile.get(TempChar);
15950  }
15951  if(SessionFile.eof()) // end of file
15952  {
15955  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
15956  }
15957  else
15958  {
15959  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
15960  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
15961  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
15962  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
15963  // now load any failed trains along with their OriginalPowerAtRail values
15964  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
15965  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
15966  double PowerDouble;
15967  while(ID != -1)
15968  {
15969  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
15972  ID = Utilities->LoadFileInt(SessionFile);
15973  }
15974  SessionFile.close();
15975  }
15976  // deal with other settings
15977  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
15978  Display->DisplayOffsetV = TempDisplayOffsetV;
15979  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
15980  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
15981  // now set attributes to 1 for all LCs with barriers down
15982  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
15983  {
15985  }
15986  Track->ChangingLCVector.clear();
15987  Track->CalcHLocMinEtc(10);
15989  SetLevel1Mode(27);
15990  if(Level2OperMode == PreStart)
15991  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
15992  { // then delay unspecified though seems to be 0
15993  PointsFlashDuration = 0.0;
15996  }
15997  else
15998  {
16002  }
16003  RlyFile = true;
16004  SetCaption(3);
16006  }
16007  }
16008  else
16009  {
16010  ShowMessage("Session file integrity check failed, unable to load session.");
16011  }
16012  Screen->Cursor = TCursor(-2); // Arrow;
16013  }
16014  Utilities->CallLogPop(1146);
16015  }
16016  catch(const Exception &e)
16017  {
16018  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
16019  {
16020  Screen->Cursor = TCursor(-2); // Arrow;
16021  OutputLog1->Caption = "";
16022  OutputLog2->Caption = "";
16023  OutputLog3->Caption = "";
16024  OutputLog4->Caption = "";
16025  OutputLog5->Caption = "";
16026  OutputLog6->Caption = "";
16027  OutputLog7->Caption = "";
16028  OutputLog8->Caption = "";
16029  OutputLog9->Caption = "";
16030  OutputLog10->Caption = "";
16031  UnicodeString MessageStr =
16032  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
16033 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
16034  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
16035  Application->Terminate();
16036  }
16037  else
16038  {
16039  ErrorLog(41, e.Message);
16040  }
16041  }
16042 }
16043 
16044 // ---------------------------------------------------------------------------
16045 
16046 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
16047 {
16048  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
16049  if(Level2OperMode == PreStart)
16050  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
16051  else
16052  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
16053  Utilities->SaveFileString(SessionFile, RailwayTitle);
16054  Utilities->SaveFileString(SessionFile, TimetableTitle);
16055  Utilities->SaveFileBool(SessionFile, PreferredRoute);
16056  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
16057  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
16058  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
16059  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
16064  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
16065  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
16066  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
16067  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
16068  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
16069  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
16070  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
16071  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
16072  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
16073  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
16074 
16096  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
16097  Utilities->CallLogPop(1211);
16098 }
16099 
16100 // ---------------------------------------------------------------------------
16101 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
16102 {
16103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
16104  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
16105 
16106  if(OpMode == "PreStart")
16108  else
16110  RailwayTitle = Utilities->LoadFileString(SessionFile);
16111  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
16112 
16113  TimetableTitle = Utilities->LoadFileString(SessionFile);
16114  PreferredRoute = Utilities->LoadFileBool(SessionFile);
16115  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
16116  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
16117  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
16118  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
16123  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
16124  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
16125  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
16126  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
16127  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
16128  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
16129  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
16130  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
16131  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
16132  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
16133 
16141  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
16155  Utilities->CallLogPop(1212);
16156 }
16157 
16158 // ---------------------------------------------------------------------------
16159 
16160 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
16161 {
16162  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
16163 
16164  AnsiString OpMode = "";
16165 
16166  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
16167  {
16168  Utilities->CallLogPop(1767);
16169  return false;
16170  }
16171  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
16172  {
16173  Utilities->CallLogPop(1768);
16174  return false;
16175  }
16176  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
16177  {
16178  Utilities->CallLogPop(1213);
16179  return false;
16180  }
16181  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
16182  {
16183  Utilities->CallLogPop(1214);
16184  return false;
16185  }
16186  if(!Utilities->CheckFileBool(SessionFile))
16187  {
16188  Utilities->CallLogPop(1216);
16189  return false;
16190  }
16191  if(!Utilities->CheckFileBool(SessionFile))
16192  {
16193  Utilities->CallLogPop(1217);
16194  return false;
16195  }
16196  if(!Utilities->CheckFileBool(SessionFile))
16197  {
16198  Utilities->CallLogPop(1218);
16199  return false;
16200  }
16201  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16202  {
16203  Utilities->CallLogPop(1409);
16204  return false;
16205  }
16206  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16207  {
16208  Utilities->CallLogPop(1486);
16209  return false;
16210  }
16211  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16212  {
16213  Utilities->CallLogPop(1487);
16214  return false;
16215  }
16216  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16217  {
16218  Utilities->CallLogPop(1488);
16219  return false;
16220  }
16221  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16222  {
16223  Utilities->CallLogPop(1489);
16224  return false;
16225  }
16226  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16227  {
16228  Utilities->CallLogPop(1528);
16229  return false;
16230  }
16231  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16232  {
16233  Utilities->CallLogPop(1725);
16234  return false;
16235  }
16236  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16237  {
16238  Utilities->CallLogPop(1726);
16239  return false;
16240  }
16241  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16242  {
16243  Utilities->CallLogPop(1727);
16244  return false;
16245  }
16246  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16247  {
16248  Utilities->CallLogPop(1728);
16249  return false;
16250  }
16251  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16252  {
16253  Utilities->CallLogPop(1730);
16254  return false;
16255  }
16256  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16257  {
16258  Utilities->CallLogPop(1731);
16259  return false;
16260  }
16261  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16262  {
16263  Utilities->CallLogPop(1732);
16264  return false;
16265  }
16266  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16267  {
16268  Utilities->CallLogPop(1733);
16269  return false;
16270  }
16271  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16272  {
16273  Utilities->CallLogPop(1734);
16274  return false;
16275  }
16276  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16277  {
16278  Utilities->CallLogPop(1789);
16279  return false;
16280  }
16281 
16282  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16283  {
16284  Utilities->CallLogPop(1737);
16285  return false;
16286  }
16287  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16288  {
16289  Utilities->CallLogPop(1738);
16290  return false;
16291  }
16292  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16293  {
16294  Utilities->CallLogPop(1739);
16295  return false;
16296  }
16297  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16298  {
16299  Utilities->CallLogPop(1740);
16300  return false;
16301  }
16302  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16303  {
16304  Utilities->CallLogPop(1741);
16305  return false;
16306  }
16307  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16308  {
16309  Utilities->CallLogPop(1742);
16310  return false;
16311  }
16312  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16313  {
16314  Utilities->CallLogPop(1743);
16315  return false;
16316  }
16317  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16318  {
16319  Utilities->CallLogPop(1744);
16320  return false;
16321  }
16322  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16323  {
16324  Utilities->CallLogPop(1745);
16325  return false;
16326  }
16327  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16328  {
16329  Utilities->CallLogPop(1746);
16330  return false;
16331  }
16332  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16333  {
16334  Utilities->CallLogPop(1747);
16335  return false;
16336  }
16337  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16338  {
16339  Utilities->CallLogPop(1748);
16340  return false;
16341  }
16342  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16343  {
16344  Utilities->CallLogPop(1749);
16345  return false;
16346  }
16347  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16348  {
16349  Utilities->CallLogPop(1750);
16350  return false;
16351  }
16352  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16353  {
16354  Utilities->CallLogPop(1751);
16355  return false;
16356  }
16357  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16358  {
16359  Utilities->CallLogPop(1752);
16360  return false;
16361  }
16362 
16363  if(!Utilities->CheckFileDouble(SessionFile))
16364  {
16365  Utilities->CallLogPop(1753);
16366  return false;
16367  }
16368  if(!Utilities->CheckFileDouble(SessionFile))
16369  {
16370  Utilities->CallLogPop(1754);
16371  return false;
16372  }
16373  if(!Utilities->CheckFileDouble(SessionFile))
16374  {
16375  Utilities->CallLogPop(1755);
16376  return false;
16377  }
16378  if(!Utilities->CheckFileDouble(SessionFile))
16379  {
16380  Utilities->CallLogPop(1756);
16381  return false;
16382  }
16383  if(!Utilities->CheckFileDouble(SessionFile))
16384  {
16385  Utilities->CallLogPop(1757);
16386  return false;
16387  }
16388  Utilities->CallLogPop(1219);
16389  return true;
16390 }
16391 
16392 // ---------------------------------------------------------------------------
16393 
16394 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
16395 {
16396  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
16397  if(!FileExists(TempTTFileName))
16398  {
16399  Utilities->CallLogPop(1862);
16400  return false;
16401  }
16402 
16403  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16404  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16405 
16406  int Handle = FileOpen(TempTTFileName, fmOpenRead);
16407  int Count = 0;
16408 
16409  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16410  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16411  // then, but nevertheless have 10 retries before giving message to be on safe side
16412  {
16413  Handle = FileOpen(TempTTFileName, fmOpenRead);
16414  Count++;
16415  Delay(1, 50); // 50mSec delay between tries
16416  if(Count > 10)
16417  {
16418  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
16419  Utilities->CallLogPop(1221);
16420  return false;
16421  }
16422  }
16423 
16424  char *Buffer = new char[10000];
16425  int BytesRead;
16426 
16427  while(true)
16428  {
16429  BytesRead = FileRead(Handle, Buffer, 10000);
16430  SessionFile.write(Buffer, BytesRead);
16431  if(BytesRead < 10000)
16432  break;
16433  }
16434  delete Buffer;
16435  FileClose(Handle);
16436 
16437  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
16438  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16439 
16440  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
16441 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
16442  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
16443  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
16444  {
16445  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
16446  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
16447  {
16448  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
16449  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
16450  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
16451  }
16452  }
16453  Utilities->CallLogPop(1220);
16454  return true;
16455 }
16456 
16457 // ---------------------------------------------------------------------------
16458 
16459 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
16460 {
16461  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
16462  if(!FileExists(TimetableFileName))
16463  {
16464  Utilities->CallLogPop(1863);
16465  return false;
16466  }
16467 
16468  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16469  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16470 
16471  int Handle = FileOpen(TimetableFileName, fmOpenRead);
16472  int Count = 0;
16473 
16474  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16475  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16476  // then, but nevertheless have 10 retries before giving message to be on safe side
16477  {
16478  Handle = FileOpen(TimetableFileName, fmOpenRead);
16479  Count++;
16480  Delay(5, 50); // 50mSec delay between tries
16481  if(Count > 10)
16482  {
16483  Utilities->CallLogPop(1835);
16484  return false;
16485  }
16486  }
16487 
16488  char *Buffer = new char[10000];
16489  int BytesRead;
16490 
16491  while(true)
16492  {
16493  BytesRead = FileRead(Handle, Buffer, 10000);
16494  ErrorFile.write(Buffer, BytesRead);
16495  if(BytesRead < 10000)
16496  break;
16497  }
16498  delete Buffer;
16499  FileClose(Handle);
16500 
16501  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
16502  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16503 
16504  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
16505  Utilities->CallLogPop(1836);
16506  return true;
16507 }
16508 
16509 // ---------------------------------------------------------------------------
16510 
16511 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16512  // the .ttb section is delimited by "***End***"
16513  // create the temporary timetable file in the working folder exactly like the original
16514 {
16515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
16516  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
16517  TrainController->SSHigh = false;
16518  TrainController->MRSHigh = false;
16519  TrainController->MRSLow = false;
16520  TrainController->MassHigh = false;
16521  TrainController->BFHigh = false;
16522  TrainController->BFLow = false;
16523  TrainController->PwrHigh = false;
16524  TrainController->SigSHigh = false;
16525  TrainController->SigSLow = false;
16526  if((TempTTFileName != "") && FileExists(TempTTFileName))
16527  {
16528  DeleteFile(TempTTFileName);
16529  }
16530  int TempTTFileNumber = 0;
16531 
16532  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
16533  {
16534  TempTTFileNumber++;
16535  }
16536  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
16537 
16538  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
16539  int Count;
16540  char Zero = '\0';
16541 
16542  if(!TTBFile.fail())
16543  {
16544  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
16545  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
16546  if(TempChar == '\n')
16547  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
16548  if(!SessionFile.getline(Buffer, 10000, '\0'))
16549  {
16550  TTBFile.close();
16551  DeleteFile(TempTTFileName);
16552  delete Buffer;
16553  Utilities->CallLogPop(1222);
16554  return false;
16555  }
16556  Count = 0;
16557  for(int x = 0; x < 10000; x++)
16558  {
16559  if(Buffer[x] != '\0')
16560  Count++;
16561  else
16562  break;
16563  }
16564  while(AnsiString(Buffer) != "***End***")
16565  {
16566  TTBFile.write(Buffer, Count);
16567  TTBFile.write(&Zero, 1);
16568 // TTBFile.write(&NewLine, 1);
16569  if(!SessionFile.getline(Buffer, 10000, '\0'))
16570  {
16571  TTBFile.close();
16572  DeleteFile(TempTTFileName);
16573  delete Buffer;
16574  Utilities->CallLogPop(1223);
16575  return false;
16576  }
16577  Count = 0;
16578  for(int x = 0; x < 10000; x++)
16579  {
16580  if(Buffer[x] != '\0')
16581  Count++;
16582  else
16583  break;
16584  }
16585  }
16586  TTBFile.close();
16587  delete Buffer;
16588 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
16589 // now create the internal timetable from the .tmp file
16590  bool GiveMessagesFalse = false;
16591  bool CheckLocationsExistInRailwayTrue = true;
16592  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
16593  {
16594  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
16595  if(TTBLFile.is_open())
16596  {
16597  bool SessionFileTrue = true;
16598  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
16599  {
16600  TTBLFile.close();
16601  DeleteFile(TempTTFileName);
16602  Utilities->CallLogPop(1224);
16603  return false;
16604  }
16605  }
16606  else
16607  {
16608  DeleteFile(TempTTFileName);
16609  Utilities->CallLogPop(1225);
16610  return false;
16611  }
16612  } // if(FileIntegrityCheck(TTBFileName.c_str()))
16613  else
16614  {
16615  DeleteFile(TempTTFileName);
16616  Utilities->CallLogPop(1226);
16617  return false;
16618  }
16619 // DeleteFile(TempTTFileName); no, need to save it for later session saves
16620 
16621  // now need to load the TrainOperatingData so can be loaded back into the timetable
16622  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
16623  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
16624  {
16625  Utilities->CallLogPop(1811);
16626  return false;
16627  }
16628  for(int x = 0; x < NumberOfTrainEntries; x++)
16629  {
16630  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
16631  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
16632  {
16633  Utilities->CallLogPop(1812);
16634  return false;
16635  }
16636  for(int y = 0; y < NumberOfTrains; y++)
16637  {
16638  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
16639  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
16640  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
16641  }
16642  }
16643  Utilities->CallLogPop(1227);
16644  return true;
16645  }
16646  else
16647  {
16648  Utilities->CallLogPop(1228);
16649  return false;
16650  }
16651 }
16652 
16653 // ---------------------------------------------------------------------------
16654 
16655 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16656  // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
16657  // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
16658  // trying to build a timetable - that's done during load
16659 {
16660  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
16661  AnsiString OutString;
16662 
16663  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
16664  {
16665  Utilities->CallLogPop(1229);
16666  return false;
16667  }
16668  while(OutString != "***End***")
16669  {
16670  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
16671  {
16672  Utilities->CallLogPop(1230);
16673  return false;
16674  }
16675  }
16676 // now need to check the TrainOperatingData, which was saved in text mode
16677  if(SessionFile.fail())
16678  {
16679  Utilities->CallLogPop(1231);
16680  return false;
16681  }
16682  int NumberOfTrainEntries;
16683 
16684  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
16685  {
16686  Utilities->CallLogPop(1232);
16687  return false;
16688  }
16689  for(int x = 0; x < NumberOfTrainEntries; x++)
16690  {
16691  int NumberOfTrains;
16692  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
16693  {
16694  Utilities->CallLogPop(1233);
16695  return false;
16696  }
16697  for(int y = 0; y < NumberOfTrains; y++)
16698  {
16699  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
16700  {
16701  Utilities->CallLogPop(1234);
16702  return false;
16703  }
16704  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
16705  {
16706  Utilities->CallLogPop(1235);
16707  return false;
16708  }
16709  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
16710  {
16711  Utilities->CallLogPop(1236);
16712  return false;
16713  }
16714  }
16715  }
16716  Utilities->CallLogPop(1237);
16717  return true;
16718 }
16719 
16720 // ---------------------------------------------------------------------------
16721 
16722 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
16723 {
16724  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
16725  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
16726  bool EndOfFile = false;
16727  int Count = 0;
16728  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
16729 
16730  while(!EndOfFile)
16731  {
16732  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16733  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
16734  { // may still have eof even if read a line (no CRLF at end), and
16735  // if so need to process it
16736  EndOfFile = true;
16737  break;
16738  }
16739  AnsiString OneLine(TrainTimetableString);
16740  bool FinalCallTrue = true;
16741  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
16742  CheckLocationsExistInRailway)) // get rid of lines before the start time
16743  {
16744  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16745  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16746  {
16747  TTBLFile.close();
16748  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
16749  }
16750  OneLine = AnsiString(TrainTimetableString);
16751  }
16752  // here when have accepted the start time
16753  if(Count == 0)
16754  {
16755  Count++; // increment past the start time
16756  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
16757  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16758  {
16759  EndOfFile = true;
16760  OneLine = "";
16761  }
16762  else
16763  OneLine = AnsiString(TrainTimetableString);
16764  }
16765  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
16766  {
16767  TTBLFile.close();
16768  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
16769  }
16770  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
16771  {
16772  TTBLFile.close();
16773  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
16774  }
16775  Count++;
16776  }
16777  TTBLFile.close();
16778  delete TrainTimetableString;
16779 // here when first pass actions completed successfully
16780  if(!TrainController->SecondPassActions(0, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
16781  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
16782  // messages given in function if errors & vector cleared
16783  {
16784  if(GiveMessages)
16785  ShowMessage("Timetable secondary integrity check failed - unable to load");
16786  Utilities->CallLogPop(1238);
16787  return false;
16788  }
16789  else
16790  {
16791 // TimetableLoaded = true;
16792  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
16793  {
16794  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
16795  {
16796  if(TimetableDialog->FileName[x] == '\\')
16797  {
16798  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
16799  SetCaption(4);
16800  break;
16801  }
16802  }
16803  }
16804 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
16805  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
16806  {
16807  Level1Mode = BaseMode;
16808  SetLevel1Mode(28);
16809  }
16810  }
16811  Utilities->CallLogPop(1239);
16812  return true;
16813 }
16814 
16815 // ---------------------------------------------------------------------------
16816 
16817 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
16818 {
16819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
16820  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
16821  bool EndOfFile = false;
16822  int Count = 0;
16823  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
16824 
16825  while(!EndOfFile)
16826  {
16827  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16828  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
16829  { // may still have eof even if read a line (no CRLF at end), and
16830  // if so need to process it
16831  EndOfFile = true;
16832  break;
16833  }
16834  AnsiString OneLine(TrainTimetableString);
16835  bool FinalCallTrue = true;
16836  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
16837  CheckLocationsExistInRailway)) // get rid of lines before the start time
16838  {
16839  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16840  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16841  {
16842  TTBLFile.close();
16843  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
16844  }
16845  OneLine = AnsiString(TrainTimetableString);
16846  }
16847  // here when have accepted the start time
16848  if(Count == 0)
16849  {
16850  Count++; // increment past the start time
16851  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
16852  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16853  {
16854  EndOfFile = true;
16855  OneLine = "";
16856  }
16857  else
16858  OneLine = AnsiString(TrainTimetableString);
16859  }
16860  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
16861  {
16862  TTBLFile.close();
16863  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
16864  }
16865  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
16866  {
16867  TTBLFile.close();
16868  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
16869  }
16870  Count++;
16871  }
16872  TTBLFile.close();
16873  delete TrainTimetableString;
16874 // here when first pass actions completed successfully
16875  if(!TrainController->SecondPassActions(1, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
16876  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
16877  // messages given in function if errors & vector cleared
16878  {
16879 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
16880 // above dropped in v2.4.0 as all called functions give own messages
16881  Utilities->CallLogPop(1665);
16882  return false;
16883  }
16884  Utilities->CallLogPop(1666);
16885  return true;
16886 }
16887 
16888 // ---------------------------------------------------------------------------
16889 
16890 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
16891 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
16892  relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
16893  before loading.
16894 
16895  Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
16896  all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
16897  which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
16898  in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
16899 
16900  Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
16901  would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
16902 */
16903 {
16904  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
16905  std::ifstream InFile(FileName.c_str());
16906 // first pass as far as timetable
16907  int NumberOfActiveElements;
16908  bool GraphicsFollow = false;
16909 
16910  if(InFile.is_open())
16911  {
16913  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float after v2.2.0
16914  {
16915  InFile.close();
16916  Utilities->CallLogPop(1240);
16917  return false;
16918  }
16919  if(!CheckInterface(0, InFile))
16920  {
16921  InFile.close();
16922  Utilities->CallLogPop(1241);
16923  return false;
16924  }
16925  // check track elements
16926  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
16927  {
16928  InFile.close();
16929  Utilities->CallLogPop(1242);
16930  return false;
16931  }
16932  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
16933  {
16934  InFile.close();
16935  Utilities->CallLogPop(1243);
16936  return false;
16937  }
16938  if(InFile.fail())
16939  {
16940  InFile.close();
16941  Utilities->CallLogPop(1244);
16942  return false;
16943  }
16944  // check text elements
16945  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
16946  {
16947  InFile.close();
16948  Utilities->CallLogPop(1245);
16949  return false;
16950  }
16951  if(!TextHandler->CheckTextElementsInFile(1, InFile))
16952  {
16953  InFile.close();
16954  Utilities->CallLogPop(1246);
16955  return false;
16956  }
16957  if(InFile.fail())
16958  {
16959  InFile.close();
16960  Utilities->CallLogPop(1247);
16961  return false;
16962  }
16963  // check PrefDir elements
16964  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
16965  {
16966  InFile.close();
16967  Utilities->CallLogPop(1248);
16968  return false;
16969  }
16970  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
16971  {
16972  InFile.close();
16973  Utilities->CallLogPop(1249);
16974  return false;
16975  }
16976  if(InFile.fail())
16977  {
16978  InFile.close();
16979  Utilities->CallLogPop(1250);
16980  return false;
16981  }
16982  // check graphics
16983  if(GraphicsFollow)
16984  {
16985  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
16986  {
16987  InFile.close();
16988  Utilities->CallLogPop(2187);
16989  return false;
16990  }
16991  if(InFile.fail())
16992  {
16993  InFile.close();
16994  Utilities->CallLogPop(2188);
16995  return false;
16996  }
16997  }
16998  // check routes
16999  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
17000  {
17001  InFile.close();
17002  Utilities->CallLogPop(1251);
17003  return false;
17004  }
17005  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
17006  {
17007  InFile.close();
17008  Utilities->CallLogPop(1252);
17009  return false;
17010  }
17011  if(InFile.fail())
17012  {
17013  InFile.close();
17014  Utilities->CallLogPop(1253);
17015  return false;
17016  }
17017  // check LockedRoutes
17018  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
17019  {
17020  InFile.close();
17021  Utilities->CallLogPop(1254);
17022  return false;
17023  }
17024  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
17025  {
17026  InFile.close();
17027  Utilities->CallLogPop(1255);
17028  return false;
17029  }
17030  if(InFile.fail())
17031  {
17032  InFile.close();
17033  Utilities->CallLogPop(1256);
17034  return false;
17035  }
17036  // check ContinuationAutoSigs
17037  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
17038  {
17039  InFile.close();
17040  Utilities->CallLogPop(1257);
17041  return false;
17042  }
17044  {
17045  InFile.close();
17046  Utilities->CallLogPop(1258);
17047  return false;
17048  }
17049  if(InFile.fail())
17050  {
17051  InFile.close();
17052  Utilities->CallLogPop(1259);
17053  return false;
17054  }
17055  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
17056  AnsiString TempString = Utilities->LoadFileString(InFile);
17057  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
17058  {
17059  InFile.close();
17060  Utilities->CallLogPop(1964);
17061  return false;
17062  }
17063  if(TempString == "***BarriersDownVector***")
17064  {
17065  if(!Track->CheckActiveLCVector(0, InFile))
17066  {
17067  InFile.close();
17068  Utilities->CallLogPop(1965);
17069  return false;
17070  }
17071  if(InFile.fail())
17072  {
17073  InFile.close();
17074  Utilities->CallLogPop(1966);
17075  return false;
17076  }
17077  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
17078  {
17079  InFile.close();
17080  Utilities->CallLogPop(1260);
17081  return false;
17082  }
17083  }
17084  // check timetable (marker string already checked immediately above)
17085  if(!CheckTimetableFromSessionFile(0, InFile))
17086  {
17087  InFile.close();
17088  Utilities->CallLogPop(1261);
17089  return false;
17090  }
17091  if(InFile.fail())
17092  {
17093  InFile.close();
17094  Utilities->CallLogPop(1262);
17095  return false;
17096  }
17097  }
17098  else
17099  {
17100  InFile.close();
17101  ShowMessage("Session file failed to open, unable to load session. Ensure that there is a folder named " + SESSION_DIR_NAME +
17102  " in the folder where the 'Railway.exe' program file resides");
17103  Utilities->CallLogPop(1263);
17104  return false;
17105  }
17106 
17107 // now ready for the 2nd pass for timetable loading and checking
17108  InFile.close();
17109  InFile.open(FileName.c_str());
17110  if(InFile.is_open())
17111  {
17113  {
17114  InFile.close();
17115  Utilities->CallLogPop(1264);
17116  return false;
17117  }
17118  if(!CheckInterface(1, InFile))
17119  {
17120  InFile.close();
17121  Utilities->CallLogPop(1265);
17122  return false;
17123  }
17124  // load track elements
17125  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
17126  {
17127  InFile.close();
17128  Utilities->CallLogPop(1266);
17129  return false;
17130  }
17131  bool GraphicsFollow = false;
17132  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
17133  if(InFile.fail())
17134  {
17135  InFile.close();
17136  Utilities->CallLogPop(1267);
17137  return false;
17138  }
17139  // check text elements
17140  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
17141  {
17142  InFile.close();
17143  Utilities->CallLogPop(1268);
17144  return false;
17145  }
17146  if(!TextHandler->CheckTextElementsInFile(2, InFile))
17147  {
17148  InFile.close();
17149  Utilities->CallLogPop(1269);
17150  return false;
17151  }
17152  if(InFile.fail())
17153  {
17154  InFile.close();
17155  Utilities->CallLogPop(1270);
17156  return false;
17157  }
17158  // check PrefDir elements
17159  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
17160  {
17161  InFile.close();
17162  Utilities->CallLogPop(1271);
17163  return false;
17164  }
17165  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
17166  {
17167  InFile.close();
17168  Utilities->CallLogPop(1272);
17169  return false;
17170  }
17171  if(InFile.fail())
17172  {
17173  InFile.close();
17174  Utilities->CallLogPop(1273);
17175  return false;
17176  }
17177  // check graphics
17178  if(GraphicsFollow)
17179  {
17180  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
17181  {
17182  InFile.close();
17183  Utilities->CallLogPop(2189);
17184  return false;
17185  }
17186  if(InFile.fail())
17187  {
17188  InFile.close();
17189  Utilities->CallLogPop(2190);
17190  return false;
17191  }
17192  }
17193  // check routes
17194  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
17195  {
17196  InFile.close();
17197  Utilities->CallLogPop(1274);
17198  return false;
17199  }
17200  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
17201  {
17202  InFile.close();
17203  Utilities->CallLogPop(1275);
17204  return false;
17205  }
17206  if(InFile.fail())
17207  {
17208  InFile.close();
17209  Utilities->CallLogPop(1276);
17210  return false;
17211  }
17212  // check LockedRoutes
17213  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
17214  {
17215  InFile.close();
17216  Utilities->CallLogPop(1277);
17217  return false;
17218  }
17219  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
17220  {
17221  InFile.close();
17222  Utilities->CallLogPop(1278);
17223  return false;
17224  }
17225  if(InFile.fail())
17226  {
17227  InFile.close();
17228  Utilities->CallLogPop(1279);
17229  return false;
17230  }
17231  // check ContinuationAutoSigs
17232  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
17233  {
17234  InFile.close();
17235  Utilities->CallLogPop(1280);
17236  return false;
17237  }
17239  {
17240  InFile.close();
17241  Utilities->CallLogPop(1281);
17242  return false;
17243  }
17244  if(InFile.fail())
17245  {
17246  InFile.close();
17247  Utilities->CallLogPop(1282);
17248  return false;
17249  }
17250  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
17251  AnsiString TempString = Utilities->LoadFileString(InFile);
17252  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
17253  {
17254  InFile.close();
17255  Utilities->CallLogPop(1967);
17256  return false;
17257  }
17258  if(TempString == "***BarriersDownVector***")
17259  {
17260  if(!Track->CheckActiveLCVector(0, InFile))
17261  {
17262  InFile.close();
17263  Utilities->CallLogPop(1968);
17264  return false;
17265  }
17266  if(InFile.fail())
17267  {
17268  InFile.close();
17269  Utilities->CallLogPop(1969);
17270  return false;
17271  }
17272  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
17273  {
17274  InFile.close();
17275  Utilities->CallLogPop(1283);
17276  return false;
17277  }
17278  }
17279  // check timetable (marker string already checked)
17280  if(!LoadTimetableFromSessionFile(1, InFile))
17281  {
17282  InFile.close();
17283  Utilities->CallLogPop(1284);
17284  return false;
17285  }
17286  if(InFile.fail())
17287  {
17288  InFile.close();
17289  Utilities->CallLogPop(1285);
17290  return false;
17291  }
17292  // check timetable clock
17293  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
17294  {
17295  InFile.close();
17296  Utilities->CallLogPop(1286);
17297  return false;
17298  }
17299  if(!Utilities->CheckFileDouble(InFile))
17300  {
17301  InFile.close();
17302  Utilities->CallLogPop(1287);
17303  return false;
17304  }
17305  // check trains
17306  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
17307  {
17308  InFile.close();
17309  Utilities->CallLogPop(1288);
17310  return false;
17311  }
17312  if(!TrainController->CheckSessionTrains(0, InFile))
17313  {
17314  InFile.close();
17315  Utilities->CallLogPop(1289);
17316  return false;
17317  }
17318  if(InFile.fail())
17319  {
17320  InFile.close();
17321  Utilities->CallLogPop(1290);
17322  return false;
17323  }
17324  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
17325  {
17326  InFile.close();
17327  Utilities->CallLogPop(1291);
17328  return false;
17329  }
17330  if(!CheckPerformanceFile(0, InFile))
17331  {
17332  InFile.close();
17333  Utilities->CallLogPop(1292);
17334  return false;
17335  }
17336  char TempChar;
17337  InFile.get(TempChar);
17338  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
17339  {
17340  InFile.get(TempChar);
17341  }
17342  if(!InFile.eof()) // additional checks needed
17343  {
17344  if(!Utilities->CheckFileString(InFile))
17345  {
17346  InFile.close();
17347  Utilities->CallLogPop(2198);
17348  return false;
17349  }
17350  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
17351  {
17352  InFile.close();
17353  Utilities->CallLogPop(2199);
17354  return false;
17355  }
17356  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
17357  {
17358  InFile.close();
17359  Utilities->CallLogPop(2200);
17360  return false;
17361  }
17362  // now check any failed trains along with their OriginalPowerAtRail values
17363  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
17364  int IDVal;
17365  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
17366  {
17367  InFile.close();
17368  Utilities->CallLogPop(2201);
17369  return false;
17370  }
17371  double PowerDouble;
17372  while(IDVal != -1)
17373  {
17374  Utilities->CheckFileDouble(InFile); // original power
17375  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
17376  {
17377  InFile.close();
17378  Utilities->CallLogPop(2202);
17379  return false;
17380  }
17381  }
17382  }
17383  InFile.close();
17384  }
17385  else
17386  {
17387  InFile.close();
17388  Utilities->CallLogPop(1293);
17389  return false;
17390  }
17391  Utilities->CallLogPop(1294);
17392  return true;
17393 }
17394 
17395 // ---------------------------------------------------------------------------
17396 
17397 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
17398  // Note that the file integrity has already been checked using CheckPerformanceFile
17399 {
17400  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
17401  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
17402  char *Buffer = new char[1000];
17403  char TempChar;
17404 
17405  InFile.get(TempChar); // '\n'
17406  InFile.getline(Buffer, 1000);
17407  TempString = AnsiString(Buffer);
17408  while(TempString != "***End of performance file***")
17409  {
17410  PerformanceLogBox->Lines->Add(TempString);
17411  Utilities->PerformanceFile << TempString.c_str() << '\n';
17412  InFile.getline(Buffer, 1000);
17413  TempString = AnsiString(Buffer);
17414  }
17415  delete Buffer;
17416  Utilities->CallLogPop(1295);
17417 }
17418 
17419 // ---------------------------------------------------------------------------
17420 
17421 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
17422 {
17423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
17424  AnsiString TempString = "";
17425  char TempChar;
17426 
17427  InFile.get(TempChar);
17428  if(TempChar != '\n')
17429  {
17430  Utilities->CallLogPop(1296);
17431  return false;
17432  }
17433  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17434  {
17435  Utilities->CallLogPop(1297);
17436  return false;
17437  }
17438  while(TempString != "***End of performance file***")
17439  {
17440  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17441  {
17442  Utilities->CallLogPop(1298);
17443  return false;
17444  }
17445  }
17446  Utilities->CallLogPop(1299);
17447  return true;
17448 }
17449 
17450 // ---------------------------------------------------------------------------
17451 
17452 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
17453 {
17454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
17455  AnsiString Text = PerformanceLogBox->Text;
17456 
17457  while(Text != "")
17458  {
17459  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
17460  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
17461  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
17462  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
17463  while((Text.Length() > 0) && Text[1] < ' ')
17464  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
17465  OutFile << OneLine.c_str() << '\n';
17466  }
17467  Utilities->CallLogPop(1300);
17468 }
17469 
17470 // ---------------------------------------------------------------------------
17471 
17473 {
17474  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
17475  if(EveryPrefDir->PrefDirSize() > 0)
17476  {
17477  if(AutoSigsFlag)
17478  {
17479  AutoSigsButton->Enabled = false;
17480  SigPrefButton->Enabled = true;
17481  UnrestrictedButton->Enabled = true;
17482  InfoPanel->Visible = true;
17483  if(Level2OperMode == PreStart)
17484  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17485  else
17486  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17487  InfoCaptionStore = InfoPanel->Caption;
17488  }
17489  else if(ConsecSignalsRoute) // PreferredRoute always same as ConsecSignalsRoute
17490  {
17491  AutoSigsButton->Enabled = true;
17492  SigPrefButton->Enabled = false;
17493  UnrestrictedButton->Enabled = true;
17494  InfoPanel->Visible = true;
17495  if(Level2OperMode == PreStart)
17496  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
17497  else
17498  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
17499  InfoCaptionStore = InfoPanel->Caption;
17500  }
17501  else
17502  {
17503  AutoSigsButton->Enabled = true;
17504  SigPrefButton->Enabled = true;
17505  UnrestrictedButton->Enabled = false;
17506  InfoPanel->Visible = true;
17507  if(Level2OperMode == PreStart)
17508  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17509  else
17510  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17511  InfoCaptionStore = InfoPanel->Caption;
17512  }
17513  }
17514  else
17515  {
17516  AutoSigsButton->Enabled = false;
17517  SigPrefButton->Enabled = false;
17518  UnrestrictedButton->Enabled = false;
17519  InfoPanel->Visible = true;
17520  if(Level2OperMode == PreStart)
17521  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17522  else
17523  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17524  InfoCaptionStore = InfoPanel->Caption;
17525  }
17527  {
17528  RouteCancelButton->Enabled = true;
17529  }
17530  else
17531  {
17532  RouteCancelButton->Enabled = false;
17533  }
17535  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
17538  Utilities->CallLogPop(1301);
17539 }
17540 
17541 // ---------------------------------------------------------------------------
17542 
17544 {
17545  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
17546  if(Display->ZoomOutFlag)
17547  {
17548  InfoPanel->Visible = true;
17549  InfoPanel->Caption = "Left click screen to zoom in at that position";
17550  }
17551  else if(Level2OperMode == Paused)
17552  {
17553  InfoPanel->Visible = true;
17554  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
17555  }
17556 // otherwise do nothing
17557  Utilities->CallLogPop(1302);
17558 }
17559 
17560 // ---------------------------------------------------------------------------
17561 
17563 {
17564  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
17565  RouteCancelButton->Enabled = false;
17566  AutoSigsButton->Enabled = false;
17567  SigPrefButton->Enabled = false;
17568  UnrestrictedButton->Enabled = false;
17569  Utilities->CallLogPop(1303);
17570 }
17571 
17572 // ---------------------------------------------------------------------------
17573 
17575  // no need for call logging as already failed
17576 {
17577 /*
17578  In order to reload as a session file:
17579 
17580  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
17581  strip out:-
17582 
17583  [since adding user graphics after prefdirs need to take this into account]
17584 
17585  up to but excluding ***Interface***
17586  from & including ***ConstructPrefDir PrefDirVector***
17587  to but excluding ***PrefDirs***
17588  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
17589  from & including ***ConstructRoute PrefDirVector***
17590  to but excluding ***Routes***
17591  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
17592  from & including ***No editing timetable*** or ***Editing timetable - [title]***
17593  to but excluding ***TimetableClock***
17594  and save as a .ssn file.
17595 
17596  In order to load as a railway file:
17597 
17598  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
17599 
17600  note or copy the version information at the top of the file
17601  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
17602  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
17603  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
17604  the next line after the two insertions should contain the number of active elements.
17605  strip out ***Text*** including the \0
17606  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
17607  strip out ***UserGraphics*** including the \0
17608  strip out from & including ***ConstructRoute PrefDirVector*** to the end of the file
17609  rename as .dev or .rly file
17610 
17611  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
17612  'Operate' then 'Exit operation'.
17613 */
17614 
17615 /*
17616  In order to extract a timetable:
17617 
17618  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
17619 
17620  set wordwrap to window on
17621  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
17622  ensure any text before start time ends with /0, otherwise don't need the \0
17623  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
17624  save as a .ttb file
17625 */
17626 
17627  Screen->Cursor = TCursor(-11); // Hourglass;
17628  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
17629  std::ofstream ErrorFile(ErrorFileStr.c_str());
17630 
17631  if(!(ErrorFile.fail()))
17632  {
17633 // save mouse position relative to mainscreen
17634  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
17635  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
17636  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
17637  Utilities->SaveFileString(ErrorFile, MouseStr);
17638  Utilities->SaveFileInt(ErrorFile, MissedTicks);
17639  Utilities->SaveFileInt(ErrorFile, TotalTicks);
17640 
17641 // save call stack
17642  Utilities->SaveFileString(ErrorFile, "***Call stack***");
17643  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
17644  {
17645  AnsiString Item = Utilities->CallLog.at(x);
17646  ErrorFile << Item.c_str() << '\n';
17647  }
17648 // save event log
17649  Utilities->SaveFileString(ErrorFile, "***Event log***");
17650  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
17651  {
17652  AnsiString Item = Utilities->EventLog.at(x);
17653  ErrorFile << Item.c_str() << '\n';
17654  }
17655 // save interface
17656  Utilities->SaveFileString(ErrorFile, "***Interface***");
17657  SaveInterface(1, ErrorFile);
17658 // save track elements
17659  Utilities->SaveFileString(ErrorFile, "***Track***");
17660  if(Track->UserGraphicVector.empty())
17661  {
17662  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
17663  }
17664  else
17665  {
17666  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
17667  }
17668 // save text elements
17669  Utilities->SaveFileString(ErrorFile, "***Text***");
17670  TextHandler->SaveText(3, ErrorFile);
17671 // save ConstructPrefDir PrefDirVector elements
17672  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
17673  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
17674 // save ConstructPrefDir SearchVector elements
17675  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
17676  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
17677 // save EveryPrefDir elements
17678  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
17679  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
17680  if(!Track->UserGraphicVector.empty())
17681  {
17682  // save user graphics
17683  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
17684  Track->SaveUserGraphics(3, ErrorFile);
17685  }
17686 // save ConstructRoute PrefDirVector
17687  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
17688  ConstructRoute->SavePrefDirVector(4, ErrorFile);
17689 // save ConstructRoute SearchVector
17690  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
17691  ConstructRoute->SaveSearchVector(1, ErrorFile);
17692 // save AllRoutes
17693  Utilities->SaveFileString(ErrorFile, "***Routes***");
17694  AllRoutes->SaveRoutes(1, ErrorFile);
17695 // save LockedRoutes
17696  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
17698 // save ContinuationAutoSigEntries
17699  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
17701 // save BarriersDownVector
17702  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
17703  Track->SaveSessionBarriersDownVector(1, ErrorFile);
17704 // save ChangingLCVector
17705  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
17706  Track->SaveChangingLCVector(0, ErrorFile);
17707 // save loaded timetable
17708  if(TimetableTitle == "")
17709  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
17710  else
17711  {
17712  Utilities->SaveFileString(ErrorFile, "***Timetable***");
17713  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
17714  {
17715  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
17716  }
17717  }
17718 // save editing timetable
17719  if(CreateEditTTTitle == "")
17720  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
17721  else
17722  {
17723  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
17724  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
17725  {
17726  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
17727  }
17728  }
17729 // save TimetableClock
17730  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
17731  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
17732 // save trains
17733  Utilities->SaveFileString(ErrorFile, "***Trains***");
17734  TrainController->SaveSessionTrains(1, ErrorFile);
17735 // save performance file
17736  Utilities->SaveFileString(ErrorFile, "***Performance file***");
17737  SavePerformanceFile(1, ErrorFile);
17738  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
17739 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
17740  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
17743  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
17744  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
17745  {
17747  {
17750  }
17751  }
17752  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
17753  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
17754 // end of v2.4.1 addition
17755 
17756  ErrorFile.close();
17757  }
17758  else
17759  {
17760  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
17761  }
17762  Screen->Cursor = TCursor(-2); // Arrow
17763 }
17764 
17765 // ---------------------------------------------------------------------------
17766 
17767 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
17768  // the .ttb section is delimited by '\n' followed by "***End***"
17769  // first create a .ttb file in the working folder exactly like the original
17770 
17771  // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
17772  // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
17773 {
17774  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
17775  if((TempTTFileName != "") && FileExists(TempTTFileName))
17776  {
17777  DeleteFile(TempTTFileName);
17778  }
17779  int TempTTFileNumber = 0;
17780 
17781  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
17782  {
17783  TempTTFileNumber++;
17784  }
17785  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
17786  int InHandle = FileOpen(InFileName, fmOpenRead);
17787  int Count = 0;
17788 
17789  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
17790  {
17791  InHandle = FileOpen(InFileName, fmOpenRead);
17792  Count++;
17793  Delay(2, 50); // 50mSec delay between tries
17794  if(Count > 10)
17795  {
17796  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
17797  Utilities->CallLogPop(1400);
17798  return;
17799  }
17800  }
17801  int OutHandle = FileCreate(TempTTFileName);
17802 
17803  Count = 0;
17804  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
17805  {
17806  OutHandle = FileCreate(TempTTFileName);
17807  Count++;
17808  Delay(3, 50); // 50mSec delay between tries
17809  if(Count > 10)
17810  {
17811  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
17812  FileClose(InHandle);
17813  Utilities->CallLogPop(1401);
17814  return;
17815  }
17816  }
17817  int CountIn, CountOut;
17818  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
17819 
17820  while(true)
17821  {
17822  CountIn = FileRead(InHandle, Buffer, 10000);
17823  CountOut = FileWrite(OutHandle, Buffer, CountIn);
17824  if(CountOut != CountIn)
17825  {
17826  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
17827  delete Buffer;
17828  FileClose(InHandle);
17829  FileClose(OutHandle);
17830  Utilities->CallLogPop(1402);
17831  return;
17832  }
17833  if(CountIn < 10000)
17834  break;
17835  }
17836  delete Buffer;
17837  FileClose(InHandle);
17838  FileClose(OutHandle);
17839  Utilities->CallLogPop(1403);
17840 }
17841 
17842 // ---------------------------------------------------------------------------
17843 
17844 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
17845 /*
17846  Rules: Platforms are fixed length elements of 100m and aren't changed. Variable length elements can't be less than 20m.
17847  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
17848 
17849  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
17850  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
17851  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
17852  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
17853  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
17854  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
17855  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
17856  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
17857  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
17858  the next XLinkPos for each succeeding element.
17859  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
17860  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
17861  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
17862  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
17863  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
17864  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
17865  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
17866  been set), an error message is given.
17867 */
17868 
17869 {
17870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
17871  bool FoundFlag;
17872 
17873 // ResetDistanceElements(4);
17874  if(ConstructPrefDir->PrefDirSize() == 0)
17875  {
17876  Utilities->CallLogPop(608);
17877  return;
17878  }
17879 // must have PrefDir size of at least 2
17880 
17881 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
17882 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
17883  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
17884  bool NamedLocPresent = false;
17885 
17886  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
17887  {
17888  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
17889  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
17890  if(!FoundFlag)
17891  {
17892  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
17893  }
17894  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
17895  VarElements++;
17896  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
17897  {
17898  VarElements++; // added in v2.4.0 for no fixed elements
17899  NamedLocPresent = true;
17900 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
17901  }
17902 
17903  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
17904  {
17905  if(SpeedLimit != -1)
17906  TE.SpeedLimit01 = SpeedLimit;
17907  }
17908  else
17909  {
17910  if(SpeedLimit != -1)
17911  TE.SpeedLimit23 = SpeedLimit;
17912  }
17913  }
17914  if(Distance == -1) // can't return before this as need to set speed limits
17915  {
17916  Utilities->CallLogPop(612);
17917  return;
17918  }
17919 
17920  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
17921  {
17922  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
17923  }
17924 
17925  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
17926  {
17927  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
17928  }
17929 
17930 /* if(NamedLocPresent) as was
17931  {
17932  ShowMessage("Named location lengths won't be changed");
17933  }
17934 */
17935 
17936  if((VarElements * 20) > Distance) // removed '+ FixedLength'
17937  {
17938  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
17939  Distance = (VarElements * 20); // removed '+ FixedLength'
17940  }
17941  if(VarElements == 0)
17942  {
17943 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
17944  ShowMessage("No elements selected"); // probably don't need this but include for safety
17945  Utilities->CallLogPop(613);
17946  return;
17947  }
17948 
17949 // second pass, set variable lengths
17950  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
17951 
17952  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
17953  {
17954  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
17955  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
17956 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
17957 // {
17958  if(NextLength < 20)
17959  NextLength = 20; // added for safety
17960  if(TE.TrackType == Points)
17961  {
17962  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
17963  {
17964  TE.Length01 = NextLength;
17965  }
17966  else
17967  {
17968  TE.Length23 = NextLength;
17969  }
17970  }
17971  else
17972  {
17973  if(PrefDirElement.GetELinkPos() < 2)
17974  {
17975  TE.Length01 = NextLength;
17976  }
17977  else
17978  {
17979  TE.Length23 = NextLength;
17980  }
17981  }
17982  RemainingDistance -= NextLength;
17983  RemainingVarElements--;
17984  if(RemainingVarElements > 0)
17985  NextLength = RemainingDistance / RemainingVarElements;
17986  else
17987  NextLength = 20;
17988 
17989 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
17990  if((RemainingDistance == 0) && (RemainingVarElements != 0))
17991  {
17992  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
17993  }
17994  if((RemainingDistance != 0) && (RemainingVarElements == 0))
17995  {
17996  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
17997  }
17998 */
17999 // }
18000  }
18001  Utilities->CallLogPop(614);
18002 }
18003 
18004 // ---------------------------------------------------------------------------
18005 
18007 {
18008  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
18010  ShowMessage("Nothing to save!");
18011  else
18012  {
18013  if(Track->IsReadyForOperation())
18014  {
18015  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
18016  }
18017  else
18018  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
18019  if(SaveRailwayDialog->Execute())
18020  {
18021  Screen->Cursor = TCursor(-11); // Hourglass;
18022  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
18023  AnsiString Extension = "";
18024  if(SaveRailwayDialog->FileName.Length() > 2)
18025  {
18026  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
18027  }
18028  if((Extension == "DEV") || (Track->IsReadyForOperation() && (Extension == "RLY")))
18029  {
18030  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
18031  if(!(VecFile.fail()))
18032  {
18036  // save track elements
18037  if(Track->UserGraphicVector.empty())
18038  {
18039  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
18040  }
18041  else
18042  {
18043  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
18044  }
18045  // save text elements
18046  TextHandler->SaveText(1, VecFile);
18047  // save PrefDir elements
18048  EveryPrefDir->SavePrefDirVector(1, VecFile);
18049  if(!Track->UserGraphicVector.empty())
18050  {
18051  // save user graphics
18052  Track->SaveUserGraphics(4, VecFile);
18053  }
18054  VecFile.close();
18055  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
18056  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
18057  {
18058  char LastChar = SavedFileName[SavedFileName.Length()];
18059  if((LastChar == 'y') || (LastChar == 'Y'))
18060  {
18061  RlyFile = true;
18062  }
18063  else
18064  {
18065  RlyFile = false;
18066  }
18067  }
18068  else
18069  {
18070  RlyFile = false;
18071  }
18072  FileChangedFlag = false;
18073  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
18074  {
18075  if(SaveRailwayDialog->FileName[x] == '\\')
18076  {
18077  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
18078  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
18079  SetCaption(7);
18080  break;
18081  }
18082  }
18083  Level1Mode = BaseMode;
18084  SetLevel1Mode(13); // to disable the save option
18085  } // if(!(VecFile.fail()))
18086  else
18087  ShowMessage("File open failed prior to save");
18088  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
18089  else
18090  {
18091  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
18092  }
18093  Screen->Cursor = TCursor(-2); // Arrow
18094  } //if(SaveRailwayDialog->Execute())
18095  }
18096  Utilities->CallLogPop(1546);
18097 }
18098 
18099 // ---------------------------------------------------------------------------
18100 
18102 { // no need for caller or log as only setting values
18103  CutMenuItem->Visible = true;
18104  CopyMenuItem->Visible = true;
18105  FlipMenuItem->Visible = true;
18106  MirrorMenuItem->Visible = true;
18107  RotRightMenuItem->Visible = true;
18108  RotLeftMenuItem->Visible = true;
18109  RotateMenuItem->Visible = true;
18110  PasteMenuItem->Visible = true;
18111 // PasteWithAttributesMenuItem->Visible = true; //added at v2.2.0
18112  DeleteMenuItem->Visible = true;
18113  SelectLengthsMenuItem->Visible = true;
18114  ReselectMenuItem->Visible = true;
18115 
18116  CutMenuItem->Enabled = false;
18117  CopyMenuItem->Enabled = false;
18118  FlipMenuItem->Enabled = false;
18119  MirrorMenuItem->Enabled = false;
18120  RotRightMenuItem->Enabled = false;
18121  RotLeftMenuItem->Enabled = false;
18122  RotateMenuItem->Enabled = false;
18123  PasteMenuItem->Enabled = false;
18124 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0
18125  DeleteMenuItem->Enabled = false;
18126  SelectLengthsMenuItem->Enabled = false;
18127  if(SelectionValid)
18128  ReselectMenuItem->Enabled = true;
18129  else
18130  ReselectMenuItem->Enabled = false;
18131 
18132  SelectBiDirPrefDirsMenuItem->Visible = false;
18133  CancelSelectionMenuItem->Enabled = true;
18134  SelectMenuItem->Enabled = true;
18135 
18136  if(NoRailway())
18137  {
18138  EditMenu->Enabled = false;
18139  }
18140  else
18141  EditMenu->Enabled = true;
18142 }
18143 
18144 // ---------------------------------------------------------------------------
18145 
18147 { // no need for caller or log as only setting values
18148  EditMenu->Enabled = true;
18149 
18150  CutMenuItem->Visible = false;
18151  CopyMenuItem->Visible = false;
18152  FlipMenuItem->Visible = false;
18153  MirrorMenuItem->Visible = false;
18154  RotRightMenuItem->Visible = false;
18155  RotLeftMenuItem->Visible = false;
18156  RotateMenuItem->Visible = false;
18157  PasteMenuItem->Visible = false;
18158 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0
18159  DeleteMenuItem->Visible = false;
18160  SelectLengthsMenuItem->Visible = false;
18161  ReselectMenuItem->Visible = false;
18162 
18163  SelectBiDirPrefDirsMenuItem->Visible = true;
18164  SelectBiDirPrefDirsMenuItem->Enabled = false;
18165  CancelSelectionMenuItem->Enabled = true;
18166  SelectMenuItem->Enabled = true;
18167 }
18168 
18169 // ---------------------------------------------------------------------------
18170 
18172 {
18173  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
18174 }
18175 
18176 // ---------------------------------------------------------------------------
18177 
18179 {
18180  SelectRect.left = 0;
18181  SelectRect.right = 0;
18182  SelectRect.top = 0;
18183  SelectRect.bottom = 0;
18184 }
18185 
18186 // ---------------------------------------------------------------------------
18187 
18188 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
18189 { // return position of erased name in HPos & VPos, return true for found & erased
18190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
18191  bool TextFound = false;
18192 
18193 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
18194 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
18195  {
18196  if(TextHandler->TextErase(4, HPos, VPos, Name))
18197  {;
18198  } // condition not used
18199  TextFound = true;
18200  }
18201  Utilities->CallLogPop(1956);
18202  return TextFound;
18203 }
18204 
18205 // ---------------------------------------------------------------------------
18206 
18207 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
18208 {
18209  if(Name == "")
18210  {
18211  return;
18212  }
18213  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
18214  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
18215  int VPosHi, VPosLo, TextPosHi, TextPosLo;
18216  TFont *Font = Display->GetFont();
18217 
18218  if(!UseEnteredPosition)
18219  {
18220  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
18221  {
18222  Utilities->CallLogPop(1561);
18223  return;
18224  }
18225  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
18226  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
18227  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
18228  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
18229  int ScreenPosLo = Display->DisplayOffsetV * 16;
18230  if(TextPosLo >= ScreenPosLo)
18231  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
18232  else if(TextPosHi < ScreenPosHi)
18233  VPos = TextPosHi;
18234  else
18235  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
18236  }
18237  TTextItem TI(HPos, VPos, Name, Font);
18238 
18239  TI.Font = Font; // may have been changed in constructor when returned as reference
18240  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
18241  Utilities->CallLogPop(1558);
18242 }
18243 
18244 // ---------------------------------------------------------------------------
18245 
18247 {
18248  try
18249  {
18250 /*
18251  ShowMessage(
18252  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
18253  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
18254  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
18255  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
18256  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
18257  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
18258  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
18259  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
18260  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
18261  "\nInterface->Left " + UnicodeString(Interface->Left) +
18262  "\nInterface->Top " + UnicodeString(Interface->Top) +
18263  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
18264  );
18265 */
18266 /*
18267  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
18268  {
18269  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
18270  {
18271  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
18272  }
18273  }
18274 */
18275 
18276 // throw Exception("Test error"); //generate an error file
18277 
18278 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
18279 
18280  }
18281  catch(const Exception &e)
18282  {
18283  ErrorLog(114, e.Message);
18284  }
18285 }
18286 
18287 // ---------------------------------------------------------------------------
18288 /*
18289  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
18290  {
18291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
18292  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
18293  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
18294  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
18295  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
18296  Utilities->CallLogPop(**);
18297  }
18298 
18299  //---------------------------------------------------------------------------
18300 
18301  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
18302  {
18303  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
18304  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
18305  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
18306  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
18307  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
18308  Utilities->CallLogPop(**);
18309  }
18310 */
18311 // ---------------------------------------------------------------------------
18312 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
18313 {
18314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
18323  Utilities->CallLogPop(1871);
18324 }
18325 
18326 // ---------------------------------------------------------------------------
18327 
18328 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
18329 {
18330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
18339  Utilities->CallLogPop(1872);
18340 }
18341 
18342 // ---------------------------------------------------------------------------
18343 
18344 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
18345  // limit it to 20 entries max
18346 {
18347  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
18349  {
18350  OAListBox->Clear();
18351  }
18353  // new at v2.2.0
18354  {
18355  Utilities->CallLogPop(2092);
18356  return;
18357  }
18358  AnsiString OpTimeToActDisplay;
18359  AnsiString OpTimeToActString;
18360  AnsiString HeadCode;
18361  float OpTimeToActFloat;
18362  TTrainController::THCandTrainPosParam HCandTrainPosParam;
18363 
18366  {
18367  if(OAListBox->Items->Count >= 20)
18368  {
18369  break;
18370  }
18371  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
18372  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
18373  HeadCode = HCandTrainPosParam.first;
18374  if(OpTimeToActFloat < 0.25) // 15 secs estimated
18375  {
18376  OpTimeToActString = "NOW";
18377  }
18378  else if(OpTimeToActFloat < 1)
18379  {
18380  OpTimeToActString = "<1";
18381  }
18382  else
18383  {
18384  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
18385  }
18386  if(OpTimeToActFloat < 60)
18387  {
18388  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
18389  OAListBox->Items->Add(OpTimeToActDisplay); // original
18390  }
18392  }
18393  Utilities->CallLogPop(2093);
18394 }
18395 
18396 // ---------------------------------------------------------------------------
18397 
18398 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
18399 {
18400  try
18401  {
18402  TrainController->LogEvent("LoadUserGraphic");
18403  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
18405  if(LoadUserGraphicDialog->Execute())
18406  {
18407  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
18408  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
18410  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
18411  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
18412  {
18413  UGME.first = SelectedGraphicFileName;
18414  TPicture *PicPtr = new TPicture;
18415  PicPtr->LoadFromFile(SelectedGraphicFileName);
18416  UGME.second = PicPtr;
18417  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
18418  {
18419  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
18420  }
18421  }
18423  SetLevel2TrackMode(65);
18424  }
18425  Utilities->CallLogPop(2191);
18426  }
18427  catch(const EInvalidGraphic &e)
18428  {
18429  ShowMessage(
18430  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
18431  }
18432  catch(const Exception &e)
18433  {
18434  ErrorLog(215, e.Message);
18435  }
18436 }
18437 
18438 // ---------------------------------------------------------------------------
18439 /*
18440  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
18441 
18442  These problems were with Borland C++Builder 4.
18443 
18444  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
18445  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
18446  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
18447  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
18448  clear what was special about this particular string.
18449  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
18450  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
18451  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
18452  This is thought to be a flaw in the compiler.
18453  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
18454  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
18455  read a null, even though the pointer had been reset to its value before the call to
18456  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
18457  that is indicated by tellg and the true pointer within the system can be different.
18458  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
18459  used for both with the new library just defined within the std namespace.
18460  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
18461  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
18462  (note - don't need the ifstream file to be open in output mode for the putback to work)
18463  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
18464  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
18465  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
18466  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
18467  file and that read by the program.
18468  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
18469  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
18470  'Frh' at the end of the entry following that for the earlier sticking point. Here
18471  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
18472  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
18473  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
18474  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
18475  would tally, though would still be wrong.
18476  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
18477  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
18478  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
18479  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
18480  lines are only separated by single newline characters.
18481 
18482  Need to check:
18483  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
18484  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
18485  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
18486 
18487  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
18488  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
18489  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
18490  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
18491 
18492  For 2: Works OK using getline().
18493 
18494  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
18495  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
18496  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
18497  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
18498 
18499  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
18500 */
18501 
18502 // ---------------------------------------------------------------------------
18503 
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15677
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:562
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3534
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:932
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:480
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:9793
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8222
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:416
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:339
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1091
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:850
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:306
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:643
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:305
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:9766
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:115
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:466
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:277
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:91
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2521
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:630
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:442
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:537
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1013
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12200
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:204
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:16817
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:545
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1067
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:358
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:304
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11248
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12015
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:850
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12337
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1574
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:200
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:339
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11618
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:104
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:646
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:461
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6324
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:327
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:17272
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:735
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:464
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:702
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:50
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:465
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4265
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:11869
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:573
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:647
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:535
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3998
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1065
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:201
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:267
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:49
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1053
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:557
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1077
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:304
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:345
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:196
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:703
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1041
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11288
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2928
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1019
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9491
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3544
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:863
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:998
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:13752
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:978
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:17562
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1938
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:263
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:383
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:340
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:686
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1044
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:50
TTrainController::LastSessionSaveTTClockTime
TDateTime LastSessionSaveTTClockTime
Definition: TrainUnit.h:641
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:919
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1504
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:522
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5064
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5091
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:112
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:7552
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:670
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:284
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:570
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:431
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:623
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1039
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:426
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:338
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:8765
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:15670
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:387
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:555
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:865
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:972
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:488
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10956
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2449
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:619
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5220
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:327
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1051
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:880
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:71
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:6967
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:428
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:369
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:18178
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:980
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:346
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:300
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:724
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:228
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11045
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:274
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:347
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:996
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6470
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:145
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8459
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:593
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:327
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:717
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:724
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1630
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8580
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:638
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:614
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:958
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:281
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:11143
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12138
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:13949
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:18312
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:6909
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:347
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:511
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1093
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:127
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:375
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16474
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:964
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:140
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1957
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:424
TTrack::IsReadyForOperation
bool IsReadyForOperation()
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:723
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:14115
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:724
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:16101
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:505
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:7568
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:926
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:17472
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:462
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:99
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3249
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3990
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:872
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:13964
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:544
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:443
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1042
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:872
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3081
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9574
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:850
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8400
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3252
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:449
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:18328
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:241
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:396
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1071
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1285
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:550
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10868
NotStarted
@ NotStarted
Definition: TrainUnit.h:80
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4149
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:736
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2050
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:414
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1017
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1040
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12162
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:861
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:767
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3144
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:244
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10268
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:768
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:131
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:642
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:506
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:307
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13844
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:63
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:335
TTrainDataEntry
Contains all data for a single train.
Definition: TrainUnit.h:177
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:761
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:16926
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5290
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:532
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:538
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8340
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17117
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8107
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:181
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1919
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:17574
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:5846
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:112
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:445
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1397
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1483
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5354
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:467
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:599
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11637
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:293
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1312
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:660
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2429
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:528
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:455
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:886
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:14068
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2872
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:275
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4562
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:14910
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:12755
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:12602
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1134
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:14006
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:629
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:49
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11111
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:690
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:308
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TInterface::SetInitialTrackModeEditMenu
void SetInitialTrackModeEditMenu()
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:18101
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:437
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2496
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12179
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9765
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1028
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4491
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1015
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:871
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:928
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11339
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5180
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:450
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1467
TTrain
Definition: TrainUnit.h:271
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:295
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:9715
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9807
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:261
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1062
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:93
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:960
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:791
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6485
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:576
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:341
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:427
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1021
GapJump
@ GapJump
Definition: TrackUnit.h:63
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:281
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:118
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:565
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:561
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:763
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:917
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:850
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:463
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:520
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11500
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:8181
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:8834
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:327
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15473
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:508
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1078
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:490
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1542
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10936
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:17543
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:327
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:903
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4519
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:197
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:529
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:252
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1055
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:321
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:195
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:633
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:253
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:15484
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:578
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:14047
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:936
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:758
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:290
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:356
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:409
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:881
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:637
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:438
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1263
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:575
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:143
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5411
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1403
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8774
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:199
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:866
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:12524
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:357
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6371
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:534
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:302
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:558
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:384
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:128
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:516
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:14172
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:18207
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:8940
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:349
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11947
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:777
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:14130
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5224
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:880
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:392
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:120
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:698
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:377
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:520
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3408
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:981
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:982
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:754
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:767
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:425
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:66
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:179
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:885
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:377
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8072
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:413
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:15627
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:371
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1685
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10371
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:134
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:16655
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1048
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3705
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6499
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1097
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1075
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:596
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:622
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:921
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7450
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:314
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11469
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:861
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:10753
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:15612
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:265
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:62
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:389
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10926
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:769
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:278
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:381
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1037
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:707
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2361
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1789
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:375
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1095
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10037
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:430
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:11795
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:12552
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:876
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:423
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1039
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:766
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:410
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1000
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:735
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4074
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:254
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:129
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:394
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:579
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:427
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:648
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:876
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:591
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:764
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4205
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:398
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1049
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:531
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1562
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:179
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:193
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9858
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:672
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:106
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:427
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:974
TTrackElement::TempMarker
bool TempMarker
Utility marker for program use.
Definition: TrackUnit.h:135
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:405
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:444
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:493
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:624
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:9065
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2412
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:639
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1111
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:273
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:327
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:968
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:379
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:373
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:724
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:881
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:365
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:446
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1264
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:135
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:540
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:850
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11164
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
Definition: TrackUnit.cpp:9620
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:434
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1122
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:751
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:298
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:504
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:799
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:18006
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5531
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1409
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9947
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:880
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7398
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:729
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1590
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1051
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1566
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:15692
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1568
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:513
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:606
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:754
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:747
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5459
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:976
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:10598
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:588
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9360
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7213
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:17767
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1572
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8909
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:191
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1057
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:608
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:586
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6271
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:738
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11078
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1595
TInterface::LengthWarningSentFlag
bool LengthWarningSentFlag
indicates that the length selection applying to all elements in the selection warning has been given,...
Definition: InterfaceUnit.h:942
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:634
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:12617
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8793
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:447
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:924
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3226
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:67
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:604
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:415
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2232
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:9667
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:69
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1064
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4544
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2139
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11712
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:535
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11542
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1060
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:548
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11318
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:915
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1816
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:362
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:815
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:644
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Plot & open (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5618
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:990
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:762
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:627
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:356
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:10898
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:521
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:353
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:425
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:51
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:707
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:334
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:137
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:745
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3457
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9647
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:616
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:89
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:645
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:198
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:348
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4056
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:560
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1032
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:419
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5139
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11561
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:11732
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:225
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2618
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:140
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:51
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:772
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:563
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5331
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3434
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
new v2.2.0, incremented in Interface.cpp, controls updating for OpTimeToActPanel
Definition: TrainUnit.h:783
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:341
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4866
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1117
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:10279
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:17397
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12217
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10897
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:880
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:12784
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8628
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:294
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:495
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:881
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:750
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:322
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1064
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4639
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:14283
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:611
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1359
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7365
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:17452
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1513
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:427
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1503
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:333
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:349
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:193
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:189
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:756
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:139
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:589
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:625
Crossover
@ Crossover
Definition: TrackUnit.h:63
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:607
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:476
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1038
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6233
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:8426
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:474
AtLocation
@ AtLocation
Definition: TrainUnit.h:67
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:147
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:73
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:984
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:16459
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:679
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15915
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:458
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:797
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:10948
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:409
Exited
@ Exited
Definition: TrainUnit.h:80
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:292
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:229
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:577
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8281
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:383
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10080
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:15356
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:553
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:8927
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:13980
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:534
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:982
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2090
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:594
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1073
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:616
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:585
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:542
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:635
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:684
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:14804
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:249
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:427
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:684
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11599
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:419
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:453
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:726
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:18171
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:403
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8191
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:494
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1891
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3718
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1570
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:992
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:369
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:519
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4143
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:180
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:735
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11772
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:320
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:546
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:327
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:15592
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3696
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:880
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:771
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9521
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11385
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:10729
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:291
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:355
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:587
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:580
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:631
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:842
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:174
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17090
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:217
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:100
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9802
TTrack::Down
@ Down
Definition: TrackUnit.h:523
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:5843
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:310
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:582
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:111
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:554
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:15435
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:62
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1390
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:988
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5950
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:842
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:595
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9379
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:427
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:232
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:485
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:203
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11252
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:15560
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6306
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:14030
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10987
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:396
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:17421
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:80
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:518
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
Timetable
@ Timetable
Definition: TrainUnit.h:56
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TInterface
Definition: InterfaceUnit.h:55
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10124
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8988
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6323
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:732
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:16046
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5402
Parapet
@ Parapet
Definition: TrackUnit.h:64
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:670
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:15585
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1030
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:507
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:724
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7693
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:15535
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:447
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:391
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:730
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:707
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:735
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:682
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:427
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:547
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:248
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:441
TInterface::SigPrefButtonClick
void __fastcall SigPrefButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2016
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:405
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:330
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:144
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:327
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:566
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:522
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1111
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:556
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:610
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:14306
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8656
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:10656
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:418
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:615
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12083
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1134
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:498
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10916
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1047
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:772
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:901
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10966
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1113
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:716
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:509
TTrack
Definition: TrackUnit.h:463
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5477
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:754
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:423
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:72
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:379
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:481
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1035
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:954
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:459
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:881
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:65
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:409
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:262
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
Definition: TrainUnit.h:787
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:626
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:867
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:946
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:618
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:853
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:218
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:251
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1100
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:67
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:564
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:475
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:45
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1120
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:584
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:279
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:825
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2596
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:12301
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5182
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:420
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5262
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7896
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1111
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4304
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3932
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:721
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:373
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:821
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1576
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:510
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:735
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:360
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3255
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:413
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:572
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10907
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:256
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:527
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:994
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1131
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5498
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:409
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:690
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1041
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2281
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:110
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:51
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:892
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:188
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:436
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:179
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:10444
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:899
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11201
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2112
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:14152
IDInt
Definition: TrackUnit.h:412
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9398
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1049
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:18398
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1134
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:79
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:296
TUtilities
Definition: Utilities.h:36
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3965
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2979
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4387
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:512
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11675
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:8674
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:789
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1083
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:181
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:552
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:428
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:189
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:276
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:318
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1137
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:8596
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:50
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:363
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:493
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:212
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5377
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:7908
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:878
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:394
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:668
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1564
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1557
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:15061
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:862
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:452
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2197
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6550
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10857
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1009
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:197
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10946
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:788
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1376
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:583
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4702
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:14059
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:913
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11010
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:617
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:881
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:76
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2908
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:57
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1007
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:110
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:87
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:362
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:636
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1269
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:639
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:637
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:8251
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:521
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:962
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:907
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:870
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:930
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:13556
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:592
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:757
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1147
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:14319
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:12279
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:657
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:11660
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11231
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1174
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:549
Points
@ Points
Definition: TrackUnit.h:63
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:752
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:12716
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:12669
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:351
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:785
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:735
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:297
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:770
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1047
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:51
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3291
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1089
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12105
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1137
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11813
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1045
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:359
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:445
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:14895
Continuation
@ Continuation
Definition: TrackUnit.h:63
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:250
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:142
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:724
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:70
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:772
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3326
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5351
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:981
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8699
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:597
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1018
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3784
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:312
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:655
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:765
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:419
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:543
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:8943
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:323
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:260
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:10487
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:16875
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11917
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:178
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:487
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:432
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1490
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:51
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:872
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:938
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1006
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1107
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:302
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11085
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6097
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:17844
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11122
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:8627
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2962
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:367
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1393
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:425
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:342
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8587
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1105
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:344
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11002
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:609
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:539
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1134
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:7612
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:559
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:429
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3359
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2894
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:826
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:911
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:194
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:484
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:944
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:880
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:986
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:460
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:53
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:351
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:950
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:4963
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10878
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:609
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:16511
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:674
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:628
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:524
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:782
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4214
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:567
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4586
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1584
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:68
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:694
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3281
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:688
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4267
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:891
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:2836
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1134
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:617
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:211
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:16722
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:235
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:4718
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:897
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:515
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17074
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:429
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1008
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4199
Connection
@ Connection
Definition: TrackUnit.h:73
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4426
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3303
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:724
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1559
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:79
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:287
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3320
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:81
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:14705
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1085
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16376
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:132
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12137
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11752
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:141
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:569
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6023
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4087
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1095
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:601
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:96
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:412
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:598
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1059
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5159
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:411
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:880
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:294
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:123
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:251
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:327
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:661
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:760
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:116
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1026
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:8221
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:102
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1045
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:386
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:6545
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:643
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:15599
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12234
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11732
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1050
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:371
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6510
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2724
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:8236
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:533
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:328
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:754
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:649
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:795
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:948
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:333
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:789
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:909
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1128
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:303
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:172
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:659
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1016
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:202
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:7644
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:343
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:600
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:14112
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:264
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:516
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:299
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:15459
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:530
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1275
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:18146
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7019
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:880
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1010
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:280
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:98
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:612
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:243
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3646
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:603
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:18246
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1020
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:9898
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:349
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:12701
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:568
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1012
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:762
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:58
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:439
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:482
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:475
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11656
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:735
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1087
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:62
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:408
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:780
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:755
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10887
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:105
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:4785
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:525
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:319
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:427
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:633
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:757
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:77
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise points: 0=set to ...
Definition: TrackUnit.h:139
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1023
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9430
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4094
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:282
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:700
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4091
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:880
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:415
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:709
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:450
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8672
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1043
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1079
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:18344
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1019
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:16394
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:574
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:400
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1860
Platform
@ Platform
Definition: TrackUnit.h:63
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:956
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:850
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:952
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:665
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1091
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4116
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:635
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:187
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:676
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:632
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:477
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:413
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:130
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1014
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:97
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1181
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11580
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13920
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8046
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:146
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:367
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:18188
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:269
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:96
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:641
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:702
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:117
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:620
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:361
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:542
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:809
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:170
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1833
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:970
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:735
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3379
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:50
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3203
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1764
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1725
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13296
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:17126
TInterface::None
@ None
Definition: InterfaceUnit.h:885
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:590
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:10296
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:74
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9371
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:647
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1005
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:245
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:630
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:749
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:793
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1069
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:389
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:645
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1079
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:663
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:759
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:42
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:966
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1029
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:64
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:526
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:913
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:152
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:523
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:16160
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:872
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:640
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:124
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3292
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:100
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1057
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9832
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:581
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1052
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:179
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:186
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5005
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6354
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:440
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:301
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:571
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:15805
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:15639
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:16646
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1111
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:960
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10007
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:876
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:489
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:1043
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9400
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:133
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:435
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:536
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11693
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:588
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:38
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:735
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:433
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5576
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:16890
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:479
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:428
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9174
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:517
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:75
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:641
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:613
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:300
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:864
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1011
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:940
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3572
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1982
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1046
Signaller
@ Signaller
Definition: TrainUnit.h:56
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:526
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2708
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1125
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:621
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:8727
Bridge
@ Bridge
Definition: TrackUnit.h:63
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:934
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8755
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:541
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:12690
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:605
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:381
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:602
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:242
Buffers
@ Buffers
Definition: TrackUnit.h:63
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:880
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:196
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:735
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:9856
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4459
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8849
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:514
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:13967
TInterface::SigPrefButton
TBitBtn * SigPrefButton
Definition: InterfaceUnit.h:195
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:885
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4029
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:451
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:551
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11048